From 8e2ab829aaf53d3cc9019b40caa0c0a93572c8cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 19:28:38 +0000 Subject: [PATCH 1/8] Update stacklok/toolhive to v0.41.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/upstream-projects.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/upstream-projects.yaml b/.github/upstream-projects.yaml index c88ca1af..79977ba1 100644 --- a/.github/upstream-projects.yaml +++ b/.github/upstream-projects.yaml @@ -44,7 +44,7 @@ projects: - id: toolhive repo: stacklok/toolhive - version: v0.40.1 + version: v0.41.0 # toolhive is a monorepo covering the CLI, the Kubernetes # operator, and the vMCP gateway. It also introduces cross- # cutting features that land in concepts/, integrations/, From 14437a8ae583056fa0efe4420d73f76b320a1c9a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 28 Jul 2026 19:29:37 +0000 Subject: [PATCH 2/8] Refresh reference assets for toolhive v0.41.0 --- docs/toolhive/reference/cli/thv_build.md | 9 +- docs/toolhive/reference/cli/thv_run.md | 2 + docs/toolhive/reference/cli/thv_skill.md | 2 + docs/toolhive/reference/cli/thv_skill_sync.md | 58 + .../reference/cli/thv_skill_upgrade.md | 62 + static/api-specs/toolhive-api.yaml | 1828 ++++++++++------- .../virtualmcpservers.schema.json | 20 +- 7 files changed, 1223 insertions(+), 758 deletions(-) create mode 100644 docs/toolhive/reference/cli/thv_skill_sync.md create mode 100644 docs/toolhive/reference/cli/thv_skill_upgrade.md diff --git a/docs/toolhive/reference/cli/thv_build.md b/docs/toolhive/reference/cli/thv_build.md index 90b23bf4..141364a4 100644 --- a/docs/toolhive/reference/cli/thv_build.md +++ b/docs/toolhive/reference/cli/thv_build.md @@ -53,10 +53,11 @@ thv build [flags] PROTOCOL [-- ARGS...] ### Options ``` - --dry-run Generate Dockerfile without building (stdout output unless -o is set) (default false) - -h, --help help for build - -o, --output string Write the Dockerfile to the specified file instead of building (default builds an image instead of generating a Dockerfile) - -t, --tag string Name and optionally a tag in the 'name:tag' format for the built image (default generates a unique image name based on the package and transport type) + --build-with stringArray Build-time dependency constraint for protocol scheme builds, interpreted per package ecosystem (uvx://: PEP 508 specifier passed to 'uv tool install --with', e.g. --build-with 'mcp<2'); errors on ecosystems without constraint support (can be specified multiple times) + --dry-run Generate Dockerfile without building (stdout output unless -o is set) (default false) + -h, --help help for build + -o, --output string Write the Dockerfile to the specified file instead of building (default builds an image instead of generating a Dockerfile) + -t, --tag string Name and optionally a tag in the 'name:tag' format for the built image (default generates a unique image name based on the package and transport type) ``` ### Options inherited from parent commands diff --git a/docs/toolhive/reference/cli/thv_run.md b/docs/toolhive/reference/cli/thv_run.md index d2e2cecf..1c8638d4 100644 --- a/docs/toolhive/reference/cli/thv_run.md +++ b/docs/toolhive/reference/cli/thv_run.md @@ -115,6 +115,7 @@ thv run [flags] SERVER_OR_IMAGE_OR_PROTOCOL [-- ARGS...] --allowed-origins stringArray Exact-match allowlist for the HTTP Origin header (repeatable). Recommended when binding publicly; loopback binds derive a default allowlist automatically, non-loopback binds log a warning when no value is supplied. Example: https://my-mcp.example.com --audit-config string Path to the audit configuration file --authz-config string Path to the authorization configuration file + --build-with stringArray Build-time dependency constraint for protocol scheme builds, interpreted per package ecosystem (uvx://: PEP 508 specifier passed to 'uv tool install --with', e.g. --build-with 'mcp<2'); errors on ecosystems without constraint support (can be specified multiple times) --ca-cert string Path to a custom CA certificate file to use for container builds --enable-audit Enable audit logging with default configuration (default false) --endpoint-prefix string Path prefix to prepend to SSE endpoint URLs (e.g., /playwright) @@ -181,6 +182,7 @@ thv run [flags] SERVER_OR_IMAGE_OR_PROTOCOL [-- ARGS...] --secret stringArray Specify a secret to be fetched from the secrets manager and set as an environment variable (format: NAME,target=TARGET) --session-ttl duration Session inactivity timeout (e.g., 30m, 2h); zero uses the default (2h) --stateless Declare the server as stateless (POST-only, no SSE). Use for MCP servers implementing streamable-HTTP stateless mode. + --strict-protocol-validation Reject client requests whose MCP-Protocol-Version header is an unknown/unsupported MCP revision with HTTP 400 (streamable-HTTP proxy only; an absent header is accepted). Off by default: any version is accepted. --target-host string Host to forward traffic to (only applicable to SSE or Streamable HTTP transport) (default "127.0.0.1") --target-port int Port for the container to expose (only applicable to SSE or Streamable HTTP transport) --thv-ca-bundle string Path to CA certificate bundle for ToolHive HTTP operations (JWKS, OIDC discovery, etc.) diff --git a/docs/toolhive/reference/cli/thv_skill.md b/docs/toolhive/reference/cli/thv_skill.md index 3a93a62f..2717cddc 100644 --- a/docs/toolhive/reference/cli/thv_skill.md +++ b/docs/toolhive/reference/cli/thv_skill.md @@ -38,6 +38,8 @@ The skill command provides subcommands to manage skills. * [thv skill install](thv_skill_install.md) - Install a skill * [thv skill list](thv_skill_list.md) - List installed skills * [thv skill push](thv_skill_push.md) - Push a built skill +* [thv skill sync](thv_skill_sync.md) - Restore project skills to match the lock file (experimental) * [thv skill uninstall](thv_skill_uninstall.md) - Uninstall a skill +* [thv skill upgrade](thv_skill_upgrade.md) - Upgrade project skills to newer pinned content (experimental) * [thv skill validate](thv_skill_validate.md) - Validate a skill definition diff --git a/docs/toolhive/reference/cli/thv_skill_sync.md b/docs/toolhive/reference/cli/thv_skill_sync.md new file mode 100644 index 00000000..f7a78f99 --- /dev/null +++ b/docs/toolhive/reference/cli/thv_skill_sync.md @@ -0,0 +1,58 @@ +--- +title: thv skill sync +hide_title: true +description: Reference for ToolHive CLI command `thv skill sync` +last_update: + author: autogenerated +slug: thv_skill_sync +mdx: + format: md +--- + +## thv skill sync + +Restore project skills to match the lock file (experimental) + +### Synopsis + +Restore a project's installed skills to match toolhive.lock.yaml. + +Experimental: requires TOOLHIVE_SKILLS_LOCK_ENABLED=true on the ToolHive +server while the lock file feature rolls out. + +Missing or drifted skills are reinstalled at their pinned digest. Use +--check to report drift without installing anything (suitable for CI). +Use --adopt to record lock entries for existing unmanaged installs, and +--prune to remove installs no longer present in the lock file. + +Unless --check is set, sync prompts for confirmation before installing — +skill content is a set of AI-followed instructions. Pass --yes to skip the +prompt (required in non-interactive contexts such as CI). + +``` +thv skill sync [flags] +``` + +### Options + +``` + --adopt Write lock entries for existing unmanaged project-scope installs + --check Report drift without installing, writing, or removing anything + --clients string Comma-separated target client apps (e.g. claude-code,opencode), or "all" for every available client + --format string Output format (json, text) (default "text") + -h, --help help for sync + --project-root string Project root path (default: auto-detected from the current directory) + --prune Remove installs no longer present in the lock file + --yes Skip the confirmation prompt (required when not running interactively) +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv skill](thv_skill.md) - Manage skills + diff --git a/docs/toolhive/reference/cli/thv_skill_upgrade.md b/docs/toolhive/reference/cli/thv_skill_upgrade.md new file mode 100644 index 00000000..c8ef974e --- /dev/null +++ b/docs/toolhive/reference/cli/thv_skill_upgrade.md @@ -0,0 +1,62 @@ +--- +title: thv skill upgrade +hide_title: true +description: Reference for ToolHive CLI command `thv skill upgrade` +last_update: + author: autogenerated +slug: thv_skill_upgrade +mdx: + format: md +--- + +## thv skill upgrade + +Upgrade project skills to newer pinned content (experimental) + +### Synopsis + +Re-resolve a project's lock entries and install newer content where available. + +Experimental: requires TOOLHIVE_SKILLS_LOCK_ENABLED=true on the ToolHive +server while the lock file feature rolls out. + +Skills pinned to an immutable reference (an OCI digest or a full git commit +hash) are reported not-upgradable — there is nothing newer to resolve to. +Use --preview to see what would change without persisting anything (OCI +sources are still fetched into the local artifact store to compare digests), +and --allow-ref-change to permit the resolved reference itself changing +(e.g. a registry entry repointed at a different repository). +--fail-on-changes evaluates the same plan and never installs: it is a CI +freshness gate. + +Unless --preview is set, upgrade prompts for confirmation before installing — +skill content is a set of AI-followed instructions. Pass --yes to skip the +prompt (required in non-interactive contexts such as CI). + +``` +thv skill upgrade [skill-name...] [flags] +``` + +### Options + +``` + --allow-ref-change Permit the resolved reference itself to change during upgrade + --clients string Comma-separated target client apps (e.g. claude-code,opencode), or "all" for every available client + --fail-on-changes Report what would change without installing anything; a CI freshness gate + --format string Output format (json, text) (default "text") + -h, --help help for upgrade + --preview Report what would change without persisting anything (OCI sources are still fetched to compare digests) + --project-root string Project root path (default: auto-detected from the current directory) + --yes Skip the confirmation prompt (required when not running interactively) +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv skill](thv_skill.md) - Manage skills + diff --git a/static/api-specs/toolhive-api.yaml b/static/api-specs/toolhive-api.yaml index ae4b482f..53225361 100644 --- a/static/api-specs/toolhive-api.yaml +++ b/static/api-specs/toolhive-api.yaml @@ -1,34 +1,136 @@ components: schemas: - github_com_stacklok_toolhive-core_registry_types.Registry: - description: Full registry data + auth.TokenValidatorConfig: + description: |- + DEPRECATED: Middleware configuration. + OIDCConfig contains OIDC configuration properties: - groups: - description: Groups is a slice of group definitions containing related MCP - servers + allowPrivateIP: + description: AllowPrivateIP allows JWKS/OIDC endpoints on private IP addresses + type: boolean + audience: + description: Audience is the expected audience for the token + type: string + authTokenFile: + description: AuthTokenFile is the path to file containing bearer token for + authentication + type: string + cacertPath: + description: CACertPath is the path to the CA certificate bundle for HTTPS + requests + type: string + clientID: + description: ClientID is the OIDC client ID + type: string + clientSecret: + description: ClientSecret is the optional OIDC client secret for introspection + type: string + insecureAllowHTTP: + description: |- + InsecureAllowHTTP allows HTTP (non-HTTPS) OIDC issuers for development/testing + WARNING: This is insecure and should NEVER be used in production + type: boolean + introspectionURL: + description: IntrospectionURL is the optional introspection endpoint for + validating tokens + type: string + issuer: + description: Issuer is the OIDC issuer URL (e.g., https://accounts.google.com) + type: string + jwksurl: + description: JWKSURL is the URL to fetch the JWKS from + type: string + resourceURL: + description: ResourceURL is the explicit resource URL for OAuth discovery + (RFC 9728) + type: string + scopes: + description: |- + Scopes is the list of OAuth scopes to advertise in the well-known endpoint (RFC 9728) + If empty, defaults to ["openid"] items: - $ref: '#/components/schemas/registry.Group' + type: string type: array - uniqueItems: false - last_updated: - description: LastUpdated is the timestamp when the registry was last updated, - in RFC3339 format + type: object + core.Workload: + properties: + created_at: + description: CreatedAt is the timestamp when the workload was created. type: string - remote_servers: - additionalProperties: - $ref: '#/components/schemas/registry.RemoteServerMetadata' - description: |- - RemoteServers is a map of server names to their corresponding remote server definitions - These are MCP servers accessed via HTTP/HTTPS using the thv proxy command - type: object - servers: + group: + description: Group is the name of the group this workload belongs to, if + any. + type: string + labels: additionalProperties: - $ref: '#/components/schemas/registry.ImageMetadata' - description: Servers is a map of server names to their corresponding server - definitions + type: string + description: Labels are the container labels (excluding standard ToolHive + labels) type: object - version: - description: Version is the schema version of the registry + name: + description: |- + Name is the name of the workload. + It is used as a unique identifier. + type: string + package: + description: Package specifies the Workload Package used to create this + Workload. + type: string + port: + description: |- + Port is the port on which the workload is exposed. + This is embedded in the URL. + type: integer + proxy_mode: + description: |- + ProxyMode is the proxy mode that clients should use to connect. + For stdio transports, this will be the proxy mode (sse or streamable-http). + For direct transports (sse/streamable-http), this will be the same as TransportType. + type: string + remote: + description: Remote indicates whether this is a remote workload (true) or + a container workload (false). + type: boolean + started_at: + description: StartedAt is when the container was last started (changes on + restart) + type: string + status: + description: Status is the current status of the workload. + enum: + - running + - stopped + - error + - starting + - stopping + - unhealthy + - removing + - unknown + - unauthenticated + - auth_retrying + - policy_stopped + type: string + status_context: + description: |- + StatusContext provides additional context about the workload's status. + The exact meaning is determined by the status and the underlying runtime. + type: string + tools: + description: ToolsFilter is the filter on tools applied to the workload. + items: + type: string + type: array + uniqueItems: false + transport_type: + description: TransportType is the type of transport used for this workload. + enum: + - stdio + - sse + - streamable-http + - inspector + type: string + url: + description: URL is the URL of the workload exposed by the ToolHive proxy. type: string type: object github_com_stacklok_toolhive_cmd_thv-operator_api_v1beta1.RateLimitConfig: @@ -120,58 +222,15 @@ components: +kubebuilder:default=1024 +optional type: integer - type: object - github_com_stacklok_toolhive_pkg_auth.TokenValidatorConfig: - description: |- - DEPRECATED: Middleware configuration. - OIDCConfig contains OIDC configuration - properties: - allowPrivateIP: - description: AllowPrivateIP allows JWKS/OIDC endpoints on private IP addresses - type: boolean - audience: - description: Audience is the expected audience for the token - type: string - authTokenFile: - description: AuthTokenFile is the path to file containing bearer token for - authentication - type: string - cacertPath: - description: CACertPath is the path to the CA certificate bundle for HTTPS - requests - type: string - clientID: - description: ClientID is the OIDC client ID - type: string - clientSecret: - description: ClientSecret is the optional OIDC client secret for introspection - type: string - insecureAllowHTTP: - description: |- - InsecureAllowHTTP allows HTTP (non-HTTPS) OIDC issuers for development/testing - WARNING: This is insecure and should NEVER be used in production - type: boolean - introspectionURL: - description: IntrospectionURL is the optional introspection endpoint for - validating tokens - type: string - issuer: - description: Issuer is the OIDC issuer URL (e.g., https://accounts.google.com) - type: string - jwksurl: - description: JWKSURL is the URL to fetch the JWKS from - type: string - resourceURL: - description: ResourceURL is the explicit resource URL for OAuth discovery - (RFC 9728) - type: string - scopes: + maxDelegationDepth: description: |- - Scopes is the list of OAuth scopes to advertise in the well-known endpoint (RFC 9728) - If empty, defaults to ["openid"] - items: - type: string - type: array + MaxDelegationDepth caps how many nested RFC 8693 "act" entries are + recorded in an audit event's delegation chain. Deeper chains are + truncated (marked with truncated=true). Defaults to 10 when unset. + +kubebuilder:validation:Minimum=1 + +kubebuilder:default=10 + +optional + type: integer type: object github_com_stacklok_toolhive_pkg_auth_awssts.Config: description: AWSStsConfig contains AWS STS token exchange configuration for @@ -241,129 +300,44 @@ components: description: RoleArn is the IAM role ARN to assume when this mapping matches. type: string type: object - github_com_stacklok_toolhive_pkg_auth_remote.Config: - description: RemoteAuthConfig contains OAuth configuration for remote MCP servers + github_com_stacklok_toolhive_pkg_auth_upstreamswap.Config: + description: |- + UpstreamSwapConfig contains configuration for upstream token swap middleware. + When set along with EmbeddedAuthServerConfig, this middleware exchanges ToolHive JWTs + for upstream IdP tokens before forwarding requests to the MCP server. properties: - authorize_url: - type: string - bearer_token: - description: Bearer token configuration (alternative to OAuth) - type: string - bearer_token_file: - type: string - cached_cimd_client_id: - description: |- - CachedCIMDClientID stores the CIMD metadata URL used as client_id when CIMD - authentication was used. Kept separate from CachedClientID (which holds - DCR-issued IDs) so the two can have independent lifecycles — DCR credential - rotation clears CachedClientID without touching the stable CIMD URL. - Read by resolveClientCredentials to send the correct client_id on token refresh. - type: string - cached_client_id: - description: |- - Cached DCR client credentials for persistence across restarts. - These are obtained during Dynamic Client Registration and needed to refresh tokens. - ClientID is stored as plain text since it's public information. + custom_header_name: + description: CustomHeaderName is the header name when HeaderStrategy is + "custom". type: string - cached_client_secret_ref: + header_strategy: + description: 'HeaderStrategy determines how to inject the token: "replace" + (default) or "custom".' type: string - cached_refresh_token_ref: + provider_name: description: |- - Cached OAuth token reference for persistence across restarts. - The refresh token is stored securely in the secret manager, and this field - contains the reference to retrieve it (e.g., "OAUTH_REFRESH_TOKEN_workload"). - This enables session restoration without requiring a new browser-based login. + ProviderName identifies which upstream provider's tokens to retrieve for injection. + This is required and must match a configured upstream provider name. type: string - cached_reg_token_ref: + type: object + github_com_stacklok_toolhive_pkg_authserver.CIMDRunConfig: + description: |- + CIMD controls client_id metadata document support. When enabled, the + embedded authorization server accepts HTTPS URLs as client_id values + and resolves them via the CIMD protocol instead of requiring DCR. + properties: + cache_fallback_ttl: description: |- - RegistrationAccessToken is used to update/delete the client registration. - Stored as a secret reference since it's sensitive. + CacheFallbackTTL is the fixed TTL applied to every cached CIMD document. + Cache-Control header parsing is not yet implemented; all entries use this value. + Format: Go duration string (e.g. "5m", "10m", "1h"). + Defaults to 5 minutes when Enabled is true and this field is omitted. + example: 5m type: string - cached_secret_expiry: + cache_max_size: description: |- - ClientSecretExpiresAt indicates when the client secret expires (if provided by the DCR server). - A zero value means the secret does not expire. - type: string - cached_token_expiry: - type: string - callback_port: - type: integer - client_id: - type: string - client_secret: - type: string - client_secret_file: - type: string - issuer: - description: OAuth endpoint configuration (from registry) - type: string - oauth_params: - additionalProperties: - type: string - description: OAuth parameters for server-specific customization - type: object - resource: - description: Resource is the OAuth 2.0 resource indicator (RFC 8707). - type: string - scope_param_name: - description: |- - ScopeParamName overrides the query parameter name used to send scopes in the - authorization URL. When empty, the standard "scope" parameter is used. - Some providers require a non-standard name (e.g., Slack uses "user_scope"). - type: string - scopes: - items: - type: string - type: array - uniqueItems: false - skip_browser: - type: boolean - timeout: - example: 5m - type: string - token_url: - type: string - use_pkce: - type: boolean - type: object - github_com_stacklok_toolhive_pkg_auth_upstreamswap.Config: - description: |- - UpstreamSwapConfig contains configuration for upstream token swap middleware. - When set along with EmbeddedAuthServerConfig, this middleware exchanges ToolHive JWTs - for upstream IdP tokens before forwarding requests to the MCP server. - properties: - custom_header_name: - description: CustomHeaderName is the header name when HeaderStrategy is - "custom". - type: string - header_strategy: - description: 'HeaderStrategy determines how to inject the token: "replace" - (default) or "custom".' - type: string - provider_name: - description: |- - ProviderName identifies which upstream provider's tokens to retrieve for injection. - This is required and must match a configured upstream provider name. - type: string - type: object - github_com_stacklok_toolhive_pkg_authserver.CIMDRunConfig: - description: |- - CIMD controls client_id metadata document support. When enabled, the - embedded authorization server accepts HTTPS URLs as client_id values - and resolves them via the CIMD protocol instead of requiring DCR. - properties: - cache_fallback_ttl: - description: |- - CacheFallbackTTL is the fixed TTL applied to every cached CIMD document. - Cache-Control header parsing is not yet implemented; all entries use this value. - Format: Go duration string (e.g. "5m", "10m", "1h"). - Defaults to 5 minutes when Enabled is true and this field is omitted. - example: 5m - type: string - cache_max_size: - description: |- - CacheMaxSize is the maximum number of CIMD documents held in the LRU cache. - Defaults to 256 when Enabled is true and this field is zero. + CacheMaxSize is the maximum number of CIMD documents held in the LRU cache. + Defaults to 256 when Enabled is true and this field is zero. type: integer enabled: description: Enabled activates CIMD client lookup when true. @@ -638,6 +612,12 @@ components: uniqueItems: false cimd: $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_authserver.CIMDRunConfig' + delegation_token_lifespan: + description: |- + DelegationTokenLifespan is the maximum lifetime for delegated tokens issued + via RFC 8693 token exchange. Specified as a Go duration string (e.g., "15m"). + If empty, defaults to 15 minutes. + type: string disable_upstream_token_injection: description: |- DisableUpstreamTokenInjection prevents the upstream swap middleware from being added. @@ -684,7 +664,7 @@ components: signing_key_config: $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_authserver.SigningKeyRunConfig' storage: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_authserver_storage.RunConfig' + $ref: '#/components/schemas/storage.RunConfig' token_lifespans: $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_authserver.TokenLifespanRunConfig' upstreams: @@ -850,96 +830,6 @@ components: If not specified, defaults to GET. type: string type: object - github_com_stacklok_toolhive_pkg_authserver_storage.ACLUserRunConfig: - description: ACLUserConfig contains ACL user authentication configuration. - properties: - password_env_var: - description: PasswordEnvVar is the environment variable containing the Redis - password. - type: string - username_env_var: - description: UsernameEnvVar is the environment variable containing the Redis - username. - type: string - type: object - github_com_stacklok_toolhive_pkg_authserver_storage.RedisRunConfig: - description: RedisConfig is the Redis-specific configuration when Type is "redis". - properties: - acl_user_config: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_authserver_storage.ACLUserRunConfig' - addr: - description: |- - Addr is the Redis server address (host:port). Required for standalone and cluster modes. - Mutually exclusive with SentinelConfig. - type: string - auth_type: - description: AuthType must be "aclUser" - only ACL user authentication is - supported. - type: string - cluster_mode: - description: ClusterMode enables the Redis Cluster protocol. Requires Addr - to be set. - type: boolean - dial_timeout: - description: DialTimeout is the timeout for establishing connections (e.g., - "5s"). - type: string - key_prefix: - description: KeyPrefix for multi-tenancy, typically "thv:auth:{ns}:{name}:". - type: string - read_timeout: - description: ReadTimeout is the timeout for read operations (e.g., "3s"). - type: string - sentinel_config: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_authserver_storage.SentinelRunConfig' - sentinel_tls: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_authserver_storage.RedisTLSRunConfig' - tls: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_authserver_storage.RedisTLSRunConfig' - write_timeout: - description: WriteTimeout is the timeout for write operations (e.g., "3s"). - type: string - type: object - github_com_stacklok_toolhive_pkg_authserver_storage.RedisTLSRunConfig: - description: SentinelTLS configures TLS for Sentinel connections. Only applies - when SentinelConfig is set. - properties: - ca_cert_file: - description: CACertFile is the path to a PEM-encoded CA certificate file. - type: string - insecure_skip_verify: - description: InsecureSkipVerify skips certificate verification. - type: boolean - type: object - github_com_stacklok_toolhive_pkg_authserver_storage.RunConfig: - description: |- - Storage configures the storage backend for the auth server. - If nil, defaults to in-memory storage. - properties: - redis_config: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_authserver_storage.RedisRunConfig' - type: - description: Type specifies the storage backend type. Defaults to "memory". - type: string - type: object - github_com_stacklok_toolhive_pkg_authserver_storage.SentinelRunConfig: - description: |- - SentinelConfig contains Sentinel-specific configuration. - Mutually exclusive with Addr. - properties: - db: - description: 'DB is the Redis database number (default: 0).' - type: integer - master_name: - description: MasterName is the name of the Redis Sentinel master. - type: string - sentinel_addrs: - description: SentinelAddrs is the list of Sentinel addresses (host:port). - items: - type: string - type: array - uniqueItems: false - type: object github_com_stacklok_toolhive_pkg_authz.Config: description: |- DEPRECATED: Middleware configuration. @@ -1036,152 +926,6 @@ components: name: $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_client.ClientApp' type: object - github_com_stacklok_toolhive_pkg_container_runtime.WorkloadStatus: - description: Current status of the workload - enum: - - running - - stopped - - error - - starting - - stopping - - unhealthy - - removing - - unknown - - unauthenticated - - auth_retrying - - policy_stopped - - running - - stopped - - error - - starting - - stopping - - unhealthy - - removing - - unknown - - unauthenticated - - auth_retrying - - policy_stopped - - running - - stopped - - error - - starting - - stopping - - unhealthy - - removing - - unknown - - unauthenticated - - auth_retrying - - policy_stopped - type: string - x-enum-varnames: - - WorkloadStatusRunning - - WorkloadStatusStopped - - WorkloadStatusError - - WorkloadStatusStarting - - WorkloadStatusStopping - - WorkloadStatusUnhealthy - - WorkloadStatusRemoving - - WorkloadStatusUnknown - - WorkloadStatusUnauthenticated - - WorkloadStatusAuthRetrying - - WorkloadStatusPolicyStopped - github_com_stacklok_toolhive_pkg_container_templates.RuntimeConfig: - description: |- - RuntimeConfig allows overriding the default runtime configuration - for this specific workload (base images and packages) - properties: - additional_packages: - description: |- - AdditionalPackages lists extra packages to install in the builder and - runtime stages. - Examples for Alpine: ["git", "make", "gcc"] - Examples for Debian: ["git", "build-essential"] - items: - type: string - type: array - uniqueItems: false - builder_image: - description: |- - BuilderImage is the full image reference for the builder stage. - An empty string signals "use the default for this transport type" during config merging. - Examples: "golang:1.26-alpine", "node:24-alpine", "python:3.14-slim" - type: string - runtime_env: - additionalProperties: - type: string - description: |- - RuntimeEnv contains environment variables to inject into the Dockerfile's - final runtime stage. Unlike BuildEnv (pkg/container/templates.TemplateData.BuildEnv), - which only affects the builder stage, these variables are baked into the - shipped image and are present in the running container's process - environment at startup. Use this for values a packaged MCP server reads at - process start (e.g. feature flags, cache backend selection), not for - build-time package manager configuration. - Keys must be uppercase with underscores, values are validated for safety. - type: object - type: object - github_com_stacklok_toolhive_pkg_core.Workload: - properties: - created_at: - description: CreatedAt is the timestamp when the workload was created. - type: string - group: - description: Group is the name of the group this workload belongs to, if - any. - type: string - labels: - additionalProperties: - type: string - description: Labels are the container labels (excluding standard ToolHive - labels) - type: object - name: - description: |- - Name is the name of the workload. - It is used as a unique identifier. - type: string - package: - description: Package specifies the Workload Package used to create this - Workload. - type: string - port: - description: |- - Port is the port on which the workload is exposed. - This is embedded in the URL. - type: integer - proxy_mode: - description: |- - ProxyMode is the proxy mode that clients should use to connect. - For stdio transports, this will be the proxy mode (sse or streamable-http). - For direct transports (sse/streamable-http), this will be the same as TransportType. - type: string - remote: - description: Remote indicates whether this is a remote workload (true) or - a container workload (false). - type: boolean - started_at: - description: StartedAt is when the container was last started (changes on - restart) - type: string - status: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_container_runtime.WorkloadStatus' - status_context: - description: |- - StatusContext provides additional context about the workload's status. - The exact meaning is determined by the status and the underlying runtime. - type: string - tools: - description: ToolsFilter is the filter on tools applied to the workload. - items: - type: string - type: array - uniqueItems: false - transport_type: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_transport_types.TransportType' - url: - description: URL is the URL of the workload exposed by the ToolHive proxy. - type: string - type: object github_com_stacklok_toolhive_pkg_groups.Group: properties: name: @@ -1202,58 +946,10 @@ components: type: array uniqueItems: false type: object - github_com_stacklok_toolhive_pkg_ignore.Config: - description: IgnoreConfig contains configuration for ignore processing - properties: - loadGlobal: - description: Whether to load global ignore patterns - type: boolean - printOverlays: - description: Whether to print resolved overlay paths for debugging - type: boolean - type: object - github_com_stacklok_toolhive_pkg_oauthproto_tokenexchange.Config: - description: TokenExchangeConfig contains token exchange configuration for external - authentication - properties: - audience: - description: Audience is the target audience for the exchanged token - type: string - client_id: - description: ClientID is the OAuth 2.0 client identifier - type: string - client_secret: - description: ClientSecret is the OAuth 2.0 client secret - type: string - external_token_header_name: - description: ExternalTokenHeaderName is the name of the custom header to - use when HeaderStrategy is "custom" - type: string - header_strategy: - description: |- - HeaderStrategy determines how to inject the token - Valid values: HeaderStrategyReplace (default), HeaderStrategyCustom - type: string - scopes: - description: Scopes is the list of scopes to request for the exchanged token - items: - type: string - type: array - uniqueItems: false - subject_token_type: - description: |- - SubjectTokenType specifies the type of the subject token being exchanged. - Common values: oauthproto.TokenTypeAccessToken (default), oauthproto.TokenTypeIDToken, oauthproto.TokenTypeJWT. - If empty, defaults to oauthproto.TokenTypeAccessToken. - type: string - token_url: - description: TokenURL is the OAuth 2.0 token endpoint URL - type: string - type: object - github_com_stacklok_toolhive_pkg_ratelimit_types.RateLimitBucket: - description: |- - PerUser token bucket configuration for this tool. - +optional + github_com_stacklok_toolhive_pkg_ratelimit_types.RateLimitBucket: + description: |- + PerUser token bucket configuration for this tool. + +optional properties: maxTokens: description: |- @@ -1337,7 +1033,7 @@ components: second instance of that middleware to the chain; the seam does not validate against this. items: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_transport_types.MiddlewareConfig' + $ref: '#/components/schemas/types.MiddlewareConfig' type: array uniqueItems: false allow_docker_gateway: @@ -1424,7 +1120,7 @@ components: description: Host is the host for the HTTP proxy type: string ignore_config: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_ignore.Config' + $ref: '#/components/schemas/ignore.Config' image: description: Image is the Docker image to run type: string @@ -1454,7 +1150,7 @@ components: MiddlewareConfigs contains the list of middleware to apply to the transport and the configuration for each middleware. items: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_transport_types.MiddlewareConfig' + $ref: '#/components/schemas/types.MiddlewareConfig' type: array uniqueItems: false mutating_webhooks: @@ -1469,7 +1165,7 @@ components: description: Name is the name of the MCP server type: string oidc_config: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_auth.TokenValidatorConfig' + $ref: '#/components/schemas/auth.TokenValidatorConfig' permission_profile_name_or_path: description: PermissionProfileNameOrPath is the name or path of the permission profile @@ -1478,7 +1174,15 @@ components: description: Port is the port for the HTTP proxy to listen on (host port) type: integer proxy_mode: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_transport_types.ProxyMode' + description: |- + ProxyMode is the effective HTTP protocol the proxy uses. + For stdio transports, this is the configured mode (sse or streamable-http). + For direct transports (sse/streamable-http), this matches the transport type. + Note: "sse" is deprecated; use "streamable-http" instead. + enum: + - sse + - streamable-http + type: string publish: description: Publish lists ports to publish to the host in format "hostPort:containerPort" items: @@ -1507,12 +1211,12 @@ components: Empty when the server was not discovered via registry lookup. type: string remote_auth_config: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_auth_remote.Config' + $ref: '#/components/schemas/remote.Config' remote_url: description: RemoteURL is the URL of the remote MCP server (if running remotely) type: string runtime_config: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_container_templates.RuntimeConfig' + $ref: '#/components/schemas/templates.RuntimeConfig' scaling_config: $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_runner.ScalingConfig' schema_version: @@ -1543,6 +1247,13 @@ components: POST-based health check instead of the default GET probe. Applies to both remote URLs and local container workloads. type: boolean + strict_protocol_validation: + description: |- + StrictProtocolValidation enables strict MCP-Protocol-Version validation + on the streamable HTTP proxy: a request whose header names an unknown + MCP revision is rejected with HTTP 400. Default false accepts any + version string (an absent header is always accepted in either mode). + type: boolean target_host: description: TargetHost is the host to forward traffic to (only applicable to SSE transport) @@ -1552,14 +1263,14 @@ components: to SSE transport) type: integer telemetry_config: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_telemetry.Config' + $ref: '#/components/schemas/telemetry.Config' thv_ca_bundle: description: |- DEPRECATED: No longer appears to be used. ThvCABundle is the path to the CA certificate bundle for ToolHive HTTP operations type: string token_exchange_config: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_oauthproto_tokenexchange.Config' + $ref: '#/components/schemas/tokenexchange.Config' tools_filter: description: |- DEPRECATED: Middleware configuration. @@ -1576,7 +1287,13 @@ components: ToolsOverride is a map from an actual tool to its overridden name and/or description type: object transport: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_transport_types.TransportType' + description: Transport is the transport mode (stdio, sse, or streamable-http) + enum: + - stdio + - sse + - streamable-http + - inspector + type: string trust_proxy_headers: description: TrustProxyHeaders indicates whether to trust X-Forwarded-* headers from reverse proxies @@ -1641,14 +1358,6 @@ components: description: Name is the redefined name of the tool type: string type: object - github_com_stacklok_toolhive_pkg_secrets.SecretParameter: - description: Bearer token for authentication (alternative to OAuth) - properties: - name: - type: string - target: - type: string - type: object github_com_stacklok_toolhive_pkg_skills.BuildResult: properties: reference: @@ -1667,6 +1376,21 @@ components: description: Reference is the OCI reference for the dependency. type: string type: object + github_com_stacklok_toolhive_pkg_skills.FailureReason: + description: Reason is a typed failure reason when Status is UpgradeStatusFailed. + enum: + - registry-unreachable + - digest-missing + - validation-rejected + - lock-write-failed + - unknown + type: string + x-enum-varnames: + - FailureReasonRegistryUnreachable + - FailureReasonDigestMissing + - FailureReasonValidationRejected + - FailureReasonLockWriteFailed + - FailureReasonUnknown github_com_stacklok_toolhive_pkg_skills.InstallStatus: description: Status is the current installation status. enum: @@ -1701,6 +1425,12 @@ components: installed_at: description: InstalledAt is the timestamp when the skill was installed. type: string + managed: + description: |- + Managed indicates this install is tracked in the project's + toolhive.lock.yaml. Only ever true for project-scoped installs. No + omitempty: false is an observable state (unmanaged), not an absence. + type: boolean metadata: $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_skills.SkillMetadata' project_root: @@ -1811,175 +1541,150 @@ components: description: Version is the semantic version of the skill. type: string type: object - github_com_stacklok_toolhive_pkg_skills.ValidationResult: + github_com_stacklok_toolhive_pkg_skills.SyncFailure: properties: - errors: - description: Errors is a list of validation errors, if any. + error: + description: Error is a human-readable description of the failure. + type: string + name: + description: Name is the skill name that failed. + type: string + reason: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_skills.FailureReason' + type: object + github_com_stacklok_toolhive_pkg_skills.SyncResult: + properties: + already_current: + description: AlreadyCurrent lists skills that already matched the lock file. items: type: string type: array uniqueItems: false - valid: - description: Valid indicates whether the skill definition is valid. - type: boolean - warnings: - description: Warnings is a list of non-blocking validation warnings, if - any. + drifted: + description: |- + Drifted lists skills whose on-disk contentDigest differed from the lock + file. Normally these are reinstalled to match it; when Check is set, + nothing is written and this field reports the drift only. items: type: string type: array uniqueItems: false - type: object - github_com_stacklok_toolhive_pkg_telemetry.Config: - description: |- - DEPRECATED: Middleware configuration. - TelemetryConfig contains the OpenTelemetry configuration - properties: - caCertPath: + failed: description: |- - CACertPath is the file path to a CA certificate bundle for the OTLP endpoint. - When set, the OTLP exporters use this CA to verify the collector's TLS certificate - instead of relying solely on the system CA pool. - +optional - type: string - customAttributes: - additionalProperties: + Failed lists skills that could not be synced, with the reason for each. + Drift alone is never reported here — see Drifted. + items: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_skills.SyncFailure' + type: array + uniqueItems: false + installed: + description: Installed lists skills that were installed or reinstalled to + match the lock file. + items: type: string + type: array + uniqueItems: false + missing: description: |- - CustomAttributes contains custom resource attributes to be added to all telemetry signals. - These are parsed from CLI flags (--otel-custom-attributes) or environment variables - (OTEL_RESOURCE_ATTRIBUTES) as key=value pairs. - +optional - type: object - enablePrometheusMetricsPath: - description: |- - EnablePrometheusMetricsPath controls whether to expose Prometheus-style /metrics endpoint. - The metrics are served on the main transport port at /metrics. - This is separate from OTLP metrics which are sent to the Endpoint. - +kubebuilder:default=false - +optional - type: boolean - endpoint: - description: |- - Endpoint is the OTLP endpoint URL - +optional - type: string - environmentVariables: - description: |- - EnvironmentVariables is a list of environment variable names that should be - included in telemetry spans as attributes. Only variables in this list will - be read from the host machine and included in spans for observability. - Example: ["NODE_ENV", "DEPLOYMENT_ENV", "SERVICE_VERSION"] - +optional + Missing lists lock entries with no corresponding install record at all + — the fresh-clone state. Normally these are installed at their pinned + reference; when Check is set, nothing is written and this field + reports the gap only. items: type: string type: array uniqueItems: false - headers: - additionalProperties: + never_managed: + description: NeverManaged lists project-scoped skills never recorded as + lock-managed. + items: type: string - description: |- - Headers contains authentication headers for the OTLP endpoint. - +optional - type: object - insecure: - description: |- - Insecure indicates whether to use HTTP instead of HTTPS for the OTLP endpoint. - +kubebuilder:default=false - +optional - type: boolean - metricsEnabled: - description: |- - MetricsEnabled controls whether OTLP metrics are enabled. - When false, OTLP metrics are not sent even if an endpoint is configured. - This is independent of EnablePrometheusMetricsPath. - +kubebuilder:default=false - +optional - type: boolean - samplingRate: - description: |- - SamplingRate is the trace sampling rate (0.0-1.0) as a string. - Only used when TracingEnabled is true. - Example: "0.05" for 5% sampling. - +kubebuilder:default="0.05" - +optional + type: array + uniqueItems: false + pruned: + description: Pruned lists removed-from-lock skills that were uninstalled + because Prune was set. + items: + type: string + type: array + uniqueItems: false + removed_from_lock: + description: RemovedFromLock lists previously managed skills absent from + the lock file. + items: + type: string + type: array + uniqueItems: false + type: object + github_com_stacklok_toolhive_pkg_skills.UpgradeOutcome: + properties: + error: + description: Error is a human-readable description of the failure, set only + when Status is UpgradeStatusFailed. type: string - serviceName: - description: |- - ServiceName is the service name for telemetry. - When omitted, defaults to the server name (e.g., VirtualMCPServer name). - +optional + name: + description: Name is the skill name. type: string - serviceVersion: + new_digest: description: |- - ServiceVersion is the service version for telemetry. - When omitted, defaults to the ToolHive version. - +optional + NewDigest is the digest the source currently resolves to. Equal to + OldDigest when Status is UpgradeStatusUpToDate. type: string - tracingEnabled: - description: |- - TracingEnabled controls whether distributed tracing is enabled. - When false, no tracer provider is created even if an endpoint is configured. - +kubebuilder:default=false - +optional - type: boolean - useLegacyAttributes: - description: |- - UseLegacyAttributes controls whether legacy (pre-MCP OTEL semconv) attribute names - are emitted alongside the new standard attribute names. When true, spans include both - old and new attribute names for backward compatibility with existing dashboards. - Currently defaults to true; this will change to false in a future release. - +kubebuilder:default=true - +optional - type: boolean + new_resolved_reference: + description: NewResolvedReference is the new resolvedReference when it changed. + type: string + old_digest: + description: OldDigest is the digest pinned in the lock file before this + operation. + type: string + reason: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_skills.FailureReason' + status: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_skills.UpgradeStatus' type: object - github_com_stacklok_toolhive_pkg_transport_types.MiddlewareConfig: + github_com_stacklok_toolhive_pkg_skills.UpgradeResult: properties: - parameters: - description: |- - Parameters is a JSON object containing the middleware parameters. - It is stored as a raw message to allow flexible parameter types. - type: object - type: - description: Type is a string representing the middleware type. - type: string + outcomes: + description: Outcomes contains one entry per skill considered for upgrade. + items: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_skills.UpgradeOutcome' + type: array + uniqueItems: false type: object - github_com_stacklok_toolhive_pkg_transport_types.ProxyMode: - description: |- - ProxyMode is the effective HTTP protocol the proxy uses. - For stdio transports, this is the configured mode (sse or streamable-http). - For direct transports (sse/streamable-http), this matches the transport type. - Note: "sse" is deprecated; use "streamable-http" instead. - enum: - - sse - - streamable-http - - sse - - streamable-http - type: string - x-enum-varnames: - - ProxyModeSSE - - ProxyModeStreamableHTTP - github_com_stacklok_toolhive_pkg_transport_types.TransportType: - description: Transport is the transport mode (stdio, sse, or streamable-http) + github_com_stacklok_toolhive_pkg_skills.UpgradeStatus: + description: Status is the outcome of the upgrade attempt. enum: - - stdio - - sse - - streamable-http - - inspector - - stdio - - sse - - streamable-http - - inspector - - stdio - - sse - - streamable-http - - inspector + - upgraded + - up-to-date + - not-upgradable + - ref-change-blocked + - failed type: string x-enum-varnames: - - TransportTypeStdio - - TransportTypeSSE - - TransportTypeStreamableHTTP - - TransportTypeInspector + - UpgradeStatusUpgraded + - UpgradeStatusUpToDate + - UpgradeStatusNotUpgradable + - UpgradeStatusRefChangeBlocked + - UpgradeStatusFailed + github_com_stacklok_toolhive_pkg_skills.ValidationResult: + properties: + errors: + description: Errors is a list of validation errors, if any. + items: + type: string + type: array + uniqueItems: false + valid: + description: Valid indicates whether the skill definition is valid. + type: boolean + warnings: + description: Warnings is a list of non-blocking validation warnings, if + any. + items: + type: string + type: array + uniqueItems: false + type: object github_com_stacklok_toolhive_pkg_webhook.Config: properties: failure_policy: @@ -2141,6 +1846,16 @@ components: - StatusNotRegistrySourced - StatusServerNotFound - StatusUnknown + ignore.Config: + description: IgnoreConfig contains configuration for ignore processing + properties: + loadGlobal: + description: Whether to load global ignore patterns + type: boolean + printOverlays: + description: Whether to print resolved overlay paths for debugging + type: boolean + type: object model.Argument: properties: choices: @@ -2655,11 +2370,11 @@ components: from (e.g. "default"). type: string runtime_config: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_container_templates.RuntimeConfig' + $ref: '#/components/schemas/templates.RuntimeConfig' secrets: description: Secret parameters to inject items: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_secrets.SecretParameter' + $ref: '#/components/schemas/secrets.SecretParameter' type: array uniqueItems: false server: @@ -2751,7 +2466,7 @@ components: description: Name of the registry type: string registry: - $ref: '#/components/schemas/github_com_stacklok_toolhive-core_registry_types.Registry' + $ref: '#/components/schemas/registry.Registry' server_count: description: Number of servers in the registry type: integer @@ -3011,7 +2726,7 @@ components: non-OIDC OAuth) type: string bearer_token: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_secrets.SecretParameter' + $ref: '#/components/schemas/secrets.SecretParameter' callback_port: description: Specific port for OAuth callback server type: integer @@ -3019,7 +2734,7 @@ components: description: OAuth client ID for authentication type: string client_secret: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_secrets.SecretParameter' + $ref: '#/components/schemas/secrets.SecretParameter' issuer: description: OAuth/OIDC issuer URL (e.g., https://accounts.google.com) type: string @@ -3115,6 +2830,35 @@ components: type: array uniqueItems: false type: object + pkg_api_v1.syncSkillsRequest: + description: Request to restore a project's installed skills to match its lock + file + properties: + adopt: + description: Adopt writes lock entries for existing unmanaged project-scope + installs + type: boolean + check: + description: Check verifies on-disk content against the lock file without + installing or writing anything + type: boolean + clients: + description: |- + Clients lists target client identifiers. Empty means every + skill-supporting client detected on this host. + items: + type: string + type: array + uniqueItems: false + project_root: + description: ProjectRoot is the project root path whose lock file should + be synced + type: string + prune: + description: Prune removes project-scoped skills installed but not present + in the lock file + type: boolean + type: object pkg_api_v1.toolOverride: description: Tool override properties: @@ -3187,11 +2931,11 @@ components: description: Port for the HTTP proxy to listen on type: integer runtime_config: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_container_templates.RuntimeConfig' + $ref: '#/components/schemas/templates.RuntimeConfig' secrets: description: Secret parameters to inject items: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_secrets.SecretParameter' + $ref: '#/components/schemas/secrets.SecretParameter' type: array uniqueItems: false target_port: @@ -3282,6 +3026,41 @@ components: type: array uniqueItems: false type: object + pkg_api_v1.upgradeSkillsRequest: + description: Request to re-resolve a project's lock entries and install newer + content + properties: + allow_ref_change: + description: AllowRefChange permits resolvedReference changes during upgrade + type: boolean + clients: + description: |- + Clients lists target client identifiers. Empty means every + skill-supporting client detected on this host. + items: + type: string + type: array + uniqueItems: false + fail_on_changes: + description: FailOnChanges exits with an error when any mutable source would + upgrade + type: boolean + names: + description: Names restricts the upgrade to specific skill names. Empty + means every entry. + items: + type: string + type: array + uniqueItems: false + preview: + description: Preview reports what would change without installing (still + fetches to compare digests) + type: boolean + project_root: + description: ProjectRoot is the project root path whose lock file should + be upgraded + type: string + type: object pkg_api_v1.validateSkillRequest: description: Request to validate a skill definition properties: @@ -3300,7 +3079,7 @@ components: workloads: description: List of container information for each workload items: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_core.Workload' + $ref: '#/components/schemas/core.Workload' type: array uniqueItems: false type: object @@ -3308,7 +3087,20 @@ components: description: Response containing workload status information properties: status: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_container_runtime.WorkloadStatus' + description: Current status of the workload + enum: + - running + - stopped + - error + - starting + - stopping + - unhealthy + - removing + - unknown + - unauthenticated + - auth_retrying + - policy_stopped + type: string type: object registry.EnvVar: properties: @@ -3608,6 +3400,37 @@ components: sigstore_url: type: string type: object + registry.Registry: + description: Full registry data + properties: + groups: + description: Groups is a slice of group definitions containing related MCP + servers + items: + $ref: '#/components/schemas/registry.Group' + type: array + uniqueItems: false + last_updated: + description: LastUpdated is the timestamp when the registry was last updated, + in RFC3339 format + type: string + remote_servers: + additionalProperties: + $ref: '#/components/schemas/registry.RemoteServerMetadata' + description: |- + RemoteServers is a map of server names to their corresponding remote server definitions + These are MCP servers accessed via HTTP/HTTPS using the thv proxy command + type: object + servers: + additionalProperties: + $ref: '#/components/schemas/registry.ImageMetadata' + description: Servers is a map of server names to their corresponding server + definitions + type: object + version: + description: Version is the schema version of the registry + type: string + type: object registry.RemoteServerMetadata: description: Remote server details (if it's a remote server) properties: @@ -3698,135 +3521,535 @@ components: description: URL is the endpoint URL for the remote MCP server (e.g., https://api.example.com/mcp) type: string type: object - registry.Skill: + registry.Skill: + properties: + _meta: + additionalProperties: {} + description: Meta is an opaque payload with extended meta data details of + the skill. + type: object + allowedTools: + description: |- + AllowedTools is the list of tools that the skill is compatible with. + This is experimental. + items: + type: string + type: array + uniqueItems: false + compatibility: + description: Compatibility is the environment requirements of the skill. + type: string + description: + description: Description is the description of the skill. + type: string + icons: + description: Icons is the list of icons for the skill. + items: + $ref: '#/components/schemas/registry.SkillIcon' + type: array + uniqueItems: false + license: + description: License is the SPDX license identifier of the skill. + type: string + metadata: + additionalProperties: {} + description: |- + Metadata is the official metadata of the skill as reported in the + SKILL.md file. + type: object + name: + description: |- + Name is the name of the skill. + The format is that of identifiers, e.g. "my-skill". + type: string + namespace: + description: |- + Namespace is the namespace of the skill. + The format is reverse-DNS, e.g. "io.github.user". + type: string + packages: + description: Packages is the list of packages for the skill. + items: + $ref: '#/components/schemas/registry.SkillPackage' + type: array + uniqueItems: false + repository: + $ref: '#/components/schemas/registry.SkillRepository' + status: + description: |- + Status is the status of the skill. + Can be one of "active", "deprecated", or "archived". + type: string + title: + description: |- + Title is the title of the skill. + This is for human consumption, not an identifier. + type: string + version: + description: |- + Version is the version of the skill. + Any non-empty string is valid, but ideally it should be either a + semantic version or a commit hash. + type: string + type: object + registry.SkillIcon: + properties: + label: + description: Label is the label of the icon. + type: string + size: + description: Size is the size of the icon. + type: string + src: + description: Src is the source of the icon. + type: string + type: + description: Type is the type of the icon. + type: string + type: object + registry.SkillPackage: + properties: + commit: + description: Commit is the commit of the package. + type: string + digest: + description: Digest is the digest of the package. + type: string + identifier: + description: Identifier is the OCI identifier of the package. + type: string + mediaType: + description: MediaType is the media type of the package. + type: string + ref: + description: Ref is the reference of the package. + type: string + registryType: + description: |- + RegistryType is the type of registry the package is from. + Can be "oci" or "git". + type: string + subfolder: + description: Subfolder is the subfolder of the package. + type: string + url: + description: URL is the URL of the package. + type: string + type: object + registry.SkillRepository: + description: Repository is the source repository of the skill. + properties: + type: + description: Type is the type of the repository. + type: string + url: + description: URL is the URL of the repository. + type: string + type: object + registry.VerifiedAttestation: + properties: + predicate: {} + predicate_type: + type: string + type: object + remote.Config: + description: RemoteAuthConfig contains OAuth configuration for remote MCP servers + properties: + authorize_url: + type: string + bearer_token: + description: Bearer token configuration (alternative to OAuth) + type: string + bearer_token_file: + type: string + cached_cimd_client_id: + description: |- + CachedCIMDClientID stores the CIMD metadata URL used as client_id when CIMD + authentication was used. Kept separate from CachedClientID (which holds + DCR-issued IDs) so the two can have independent lifecycles — DCR credential + rotation clears CachedClientID without touching the stable CIMD URL. + Read by resolveClientCredentials to send the correct client_id on token refresh. + type: string + cached_client_id: + description: |- + Cached DCR client credentials for persistence across restarts. + These are obtained during Dynamic Client Registration and needed to refresh tokens. + ClientID is stored as plain text since it's public information. + type: string + cached_client_secret_ref: + type: string + cached_dcr_callback_port: + description: |- + CachedDCRCallbackPort is the callback port that was actually registered + during DCR. It may differ from CallbackPort when the requested port was + unavailable and a fallback port was selected. + type: integer + cached_refresh_token_ref: + description: |- + Cached OAuth token reference for persistence across restarts. + The refresh token is stored securely in the secret manager, and this field + contains the reference to retrieve it (e.g., "OAUTH_REFRESH_TOKEN_workload"). + This enables session restoration without requiring a new browser-based login. + type: string + cached_reg_client_uri: + description: |- + CachedRegClientURI is the registration_client_uri from the DCR response. + This is the endpoint used for RFC 7592 client read/update/delete operations. + Stored as plain text since it is not sensitive. + type: string + cached_reg_token_ref: + description: |- + CachedRegTokenRef is a secret manager reference to the registration_access_token + returned in the DCR response. Used for RFC 7592 client update operations. + Stored as a secret reference since it's sensitive. + type: string + cached_secret_expiry: + description: |- + ClientSecretExpiresAt indicates when the client secret expires (if provided by the DCR server). + A zero value means the secret does not expire. + type: string + cached_token_auth_method: + description: |- + CachedTokenEndpointAuthMethod is the auth method used for the token endpoint + (e.g., "client_secret_basic", "none"). Persisted for RFC 7592 updates. + type: string + cached_token_expiry: + type: string + callback_port: + type: integer + client_id: + type: string + client_secret: + type: string + client_secret_file: + type: string + issuer: + description: OAuth endpoint configuration (from registry) + type: string + oauth_params: + additionalProperties: + type: string + description: OAuth parameters for server-specific customization + type: object + resource: + description: Resource is the OAuth 2.0 resource indicator (RFC 8707). + type: string + scope_param_name: + description: |- + ScopeParamName overrides the query parameter name used to send scopes in the + authorization URL. When empty, the standard "scope" parameter is used. + Some providers require a non-standard name (e.g., Slack uses "user_scope"). + type: string + scopes: + items: + type: string + type: array + uniqueItems: false + skip_browser: + type: boolean + timeout: + example: 5m + type: string + token_url: + type: string + use_pkce: + type: boolean + type: object + secrets.SecretParameter: + description: Bearer token for authentication (alternative to OAuth) + properties: + name: + type: string + target: + type: string + type: object + storage.ACLUserRunConfig: + description: ACLUserConfig contains ACL user authentication configuration. + properties: + password_env_var: + description: PasswordEnvVar is the environment variable containing the Redis + password. + type: string + username_env_var: + description: UsernameEnvVar is the environment variable containing the Redis + username. + type: string + type: object + storage.RedisRunConfig: + description: RedisConfig is the Redis-specific configuration when Type is "redis". + properties: + acl_user_config: + $ref: '#/components/schemas/storage.ACLUserRunConfig' + addr: + description: |- + Addr is the Redis server address (host:port). Required for standalone and cluster modes. + Mutually exclusive with SentinelConfig. + type: string + auth_type: + description: AuthType must be "aclUser" - only ACL user authentication is + supported. + type: string + cluster_mode: + description: ClusterMode enables the Redis Cluster protocol. Requires Addr + to be set. + type: boolean + dial_timeout: + description: DialTimeout is the timeout for establishing connections (e.g., + "5s"). + type: string + key_prefix: + description: KeyPrefix for multi-tenancy, typically "thv:auth:{ns}:{name}:". + type: string + read_timeout: + description: ReadTimeout is the timeout for read operations (e.g., "3s"). + type: string + sentinel_config: + $ref: '#/components/schemas/storage.SentinelRunConfig' + sentinel_tls: + $ref: '#/components/schemas/storage.RedisTLSRunConfig' + tls: + $ref: '#/components/schemas/storage.RedisTLSRunConfig' + write_timeout: + description: WriteTimeout is the timeout for write operations (e.g., "3s"). + type: string + type: object + storage.RedisTLSRunConfig: + description: SentinelTLS configures TLS for Sentinel connections. Only applies + when SentinelConfig is set. + properties: + ca_cert_file: + description: CACertFile is the path to a PEM-encoded CA certificate file. + type: string + insecure_skip_verify: + description: InsecureSkipVerify skips certificate verification. + type: boolean + type: object + storage.RunConfig: + description: |- + Storage configures the storage backend for the auth server. + If nil, defaults to in-memory storage. + properties: + redis_config: + $ref: '#/components/schemas/storage.RedisRunConfig' + type: + description: Type specifies the storage backend type. Defaults to "memory". + type: string + type: object + storage.SentinelRunConfig: + description: |- + SentinelConfig contains Sentinel-specific configuration. + Mutually exclusive with Addr. + properties: + db: + description: 'DB is the Redis database number (default: 0).' + type: integer + master_name: + description: MasterName is the name of the Redis Sentinel master. + type: string + sentinel_addrs: + description: SentinelAddrs is the list of Sentinel addresses (host:port). + items: + type: string + type: array + uniqueItems: false + type: object + telemetry.Config: + description: |- + DEPRECATED: Middleware configuration. + TelemetryConfig contains the OpenTelemetry configuration + properties: + caCertPath: + description: |- + CACertPath is the file path to a CA certificate bundle for the OTLP endpoint. + When set, the OTLP exporters use this CA to verify the collector's TLS certificate + instead of relying solely on the system CA pool. + +optional + type: string + customAttributes: + additionalProperties: + type: string + description: |- + CustomAttributes contains custom resource attributes to be added to all telemetry signals. + These are parsed from CLI flags (--otel-custom-attributes) or environment variables + (OTEL_RESOURCE_ATTRIBUTES) as key=value pairs. + +optional + type: object + enablePrometheusMetricsPath: + description: |- + EnablePrometheusMetricsPath controls whether to expose Prometheus-style /metrics endpoint. + The metrics are served on the main transport port at /metrics. + This is separate from OTLP metrics which are sent to the Endpoint. + +kubebuilder:default=false + +optional + type: boolean + endpoint: + description: |- + Endpoint is the OTLP endpoint URL + +optional + type: string + environmentVariables: + description: |- + EnvironmentVariables is a list of environment variable names that should be + included in telemetry spans as attributes. Only variables in this list will + be read from the host machine and included in spans for observability. + Example: ["NODE_ENV", "DEPLOYMENT_ENV", "SERVICE_VERSION"] + +optional + items: + type: string + type: array + uniqueItems: false + headers: + additionalProperties: + type: string + description: |- + Headers contains authentication headers for the OTLP endpoint. + +optional + type: object + insecure: + description: |- + Insecure indicates whether to use HTTP instead of HTTPS for the OTLP endpoint. + +kubebuilder:default=false + +optional + type: boolean + metricsEnabled: + description: |- + MetricsEnabled controls whether OTLP metrics are enabled. + When false, OTLP metrics are not sent even if an endpoint is configured. + This is independent of EnablePrometheusMetricsPath. + +kubebuilder:default=false + +optional + type: boolean + samplingRate: + description: |- + SamplingRate is the trace sampling rate (0.0-1.0) as a string. + Only used when TracingEnabled is true. + Example: "0.05" for 5% sampling. + +kubebuilder:default="0.05" + +optional + type: string + serviceName: + description: |- + ServiceName is the service name for telemetry. + When omitted, defaults to the server name (e.g., VirtualMCPServer name). + +optional + type: string + serviceVersion: + description: |- + ServiceVersion is the service version for telemetry. + When omitted, defaults to the ToolHive version. + +optional + type: string + tracingEnabled: + description: |- + TracingEnabled controls whether distributed tracing is enabled. + When false, no tracer provider is created even if an endpoint is configured. + +kubebuilder:default=false + +optional + type: boolean + useLegacyAttributes: + description: |- + UseLegacyAttributes controls whether legacy (pre-MCP OTEL semconv) attribute names + are emitted alongside the new standard attribute names. When true, spans include both + old and new attribute names for backward compatibility with existing dashboards. + Currently defaults to true; this will change to false in a future release. + +kubebuilder:default=true + +optional + type: boolean + type: object + templates.RuntimeConfig: + description: |- + RuntimeConfig allows overriding the default runtime configuration + for this specific workload (base images and packages) properties: - _meta: - additionalProperties: {} - description: Meta is an opaque payload with extended meta data details of - the skill. - type: object - allowedTools: + additional_packages: description: |- - AllowedTools is the list of tools that the skill is compatible with. - This is experimental. + AdditionalPackages lists extra packages to install in the builder and + runtime stages. + Examples for Alpine: ["git", "make", "gcc"] + Examples for Debian: ["git", "build-essential"] items: type: string type: array uniqueItems: false - compatibility: - description: Compatibility is the environment requirements of the skill. - type: string - description: - description: Description is the description of the skill. - type: string - icons: - description: Icons is the list of icons for the skill. - items: - $ref: '#/components/schemas/registry.SkillIcon' - type: array - uniqueItems: false - license: - description: License is the SPDX license identifier of the skill. - type: string - metadata: - additionalProperties: {} - description: |- - Metadata is the official metadata of the skill as reported in the - SKILL.md file. - type: object - name: - description: |- - Name is the name of the skill. - The format is that of identifiers, e.g. "my-skill". - type: string - namespace: - description: |- - Namespace is the namespace of the skill. - The format is reverse-DNS, e.g. "io.github.user". - type: string - packages: - description: Packages is the list of packages for the skill. + build_with: + description: |- + BuildWith lists build-time dependency constraints, interpreted per + package ecosystem. For uvx:// builds these are PEP 508 requirement + specifiers passed to `uv tool install --with`, used to constrain + transitive dependencies the package itself leaves unbounded + (e.g. "mcp<2"). Ecosystems without constraint support (npx://, go://) + reject a non-empty BuildWith at build time. items: - $ref: '#/components/schemas/registry.SkillPackage' + type: string type: array uniqueItems: false - repository: - $ref: '#/components/schemas/registry.SkillRepository' - status: - description: |- - Status is the status of the skill. - Can be one of "active", "deprecated", or "archived". - type: string - title: + builder_image: description: |- - Title is the title of the skill. - This is for human consumption, not an identifier. + BuilderImage is the full image reference for the builder stage. + An empty string signals "use the default for this transport type" during config merging. + Examples: "golang:1.26-alpine", "node:24-alpine", "python:3.14-slim" type: string - version: + runtime_env: + additionalProperties: + type: string description: |- - Version is the version of the skill. - Any non-empty string is valid, but ideally it should be either a - semantic version or a commit hash. - type: string - type: object - registry.SkillIcon: - properties: - label: - description: Label is the label of the icon. - type: string - size: - description: Size is the size of the icon. - type: string - src: - description: Src is the source of the icon. - type: string - type: - description: Type is the type of the icon. - type: string + RuntimeEnv contains environment variables to inject into the Dockerfile's + final runtime stage. Unlike BuildEnv (pkg/container/templates.TemplateData.BuildEnv), + which only affects the builder stage, these variables are baked into the + shipped image and are present in the running container's process + environment at startup. Use this for values a packaged MCP server reads at + process start (e.g. feature flags, cache backend selection), not for + build-time package manager configuration. + Keys must be uppercase with underscores, values are validated for safety. + type: object type: object - registry.SkillPackage: + tokenexchange.Config: + description: TokenExchangeConfig contains token exchange configuration for external + authentication properties: - commit: - description: Commit is the commit of the package. - type: string - digest: - description: Digest is the digest of the package. + audience: + description: Audience is the target audience for the exchanged token type: string - identifier: - description: Identifier is the OCI identifier of the package. + client_id: + description: ClientID is the OAuth 2.0 client identifier type: string - mediaType: - description: MediaType is the media type of the package. + client_secret: + description: ClientSecret is the OAuth 2.0 client secret type: string - ref: - description: Ref is the reference of the package. + external_token_header_name: + description: ExternalTokenHeaderName is the name of the custom header to + use when HeaderStrategy is "custom" type: string - registryType: + header_strategy: description: |- - RegistryType is the type of registry the package is from. - Can be "oci" or "git". + HeaderStrategy determines how to inject the token + Valid values: HeaderStrategyReplace (default), HeaderStrategyCustom type: string - subfolder: - description: Subfolder is the subfolder of the package. + scopes: + description: Scopes is the list of scopes to request for the exchanged token + items: + type: string + type: array + uniqueItems: false + subject_token_type: + description: |- + SubjectTokenType specifies the type of the subject token being exchanged. + Common values: oauthproto.TokenTypeAccessToken (default), oauthproto.TokenTypeIDToken, oauthproto.TokenTypeJWT. + If empty, defaults to oauthproto.TokenTypeAccessToken. type: string - url: - description: URL is the URL of the package. + token_url: + description: TokenURL is the OAuth 2.0 token endpoint URL type: string type: object - registry.SkillRepository: - description: Repository is the source repository of the skill. + types.MiddlewareConfig: properties: + parameters: + description: |- + Parameters is a JSON object containing the middleware parameters. + It is stored as a raw message to allow flexible parameter types. + type: object type: - description: Type is the type of the repository. - type: string - url: - description: URL is the URL of the repository. - type: string - type: object - registry.VerifiedAttestation: - properties: - predicate: {} - predicate_type: + description: Type is a string representing the middleware type. type: string type: object v0.ServerJSON: @@ -5175,6 +5398,109 @@ paths: summary: Push a skill tags: - skills + /api/v1beta/skills/sync: + post: + description: Restore a project's installed skills to match toolhive.lock.yaml + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + - $ref: '#/components/schemas/pkg_api_v1.syncSkillsRequest' + description: Sync request + summary: request + description: Sync request + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_skills.SyncResult' + description: OK + "400": + content: + application/json: + schema: + type: string + description: Bad Request + "403": + content: + application/json: + schema: + type: string + description: Forbidden (feature not enabled) + "500": + content: + application/json: + schema: + type: string + description: Internal Server Error + "501": + content: + application/json: + schema: + type: string + description: Not Implemented + summary: Sync project skills from the lock file + tags: + - skills + /api/v1beta/skills/upgrade: + post: + description: Re-resolve a project's lock entries and install newer content where + available + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + - $ref: '#/components/schemas/pkg_api_v1.upgradeSkillsRequest' + description: Upgrade request + summary: request + description: Upgrade request + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_skills.UpgradeResult' + description: OK + "400": + content: + application/json: + schema: + type: string + description: Bad Request + "403": + content: + application/json: + schema: + type: string + description: Forbidden (feature not enabled) + "404": + content: + application/json: + schema: + type: string + description: Not Found (a requested name is not in the lock file) + "500": + content: + application/json: + schema: + type: string + description: Internal Server Error + "501": + content: + application/json: + schema: + type: string + description: Not Implemented + summary: Upgrade project skills + tags: + - skills /api/v1beta/skills/validate: post: description: Validate a skill definition diff --git a/static/api-specs/toolhive-crds/virtualmcpservers.schema.json b/static/api-specs/toolhive-crds/virtualmcpservers.schema.json index a9001513..ed9b19a3 100644 --- a/static/api-specs/toolhive-crds/virtualmcpservers.schema.json +++ b/static/api-specs/toolhive-crds/virtualmcpservers.schema.json @@ -785,11 +785,11 @@ "properties": { "prefixFormat": { "default": "{workload}_", - "description": "PrefixFormat defines the prefix format for the \"prefix\" strategy.\nSupports placeholders: {workload}, {workload}_, {workload}.", + "description": "PrefixFormat defines the prefix format for the \"prefix\" tool strategy\nand for backend-prefixed prompt names (the default for every prompt;\nunder the \"priority\" strategy, backends listed in priorityOrder keep\ntheir own prompt names).\nSupports placeholders: {workload}, {workload}_, {workload}.", "type": "string" }, "priorityOrder": { - "description": "PriorityOrder defines the workload priority order for the \"priority\" strategy.", + "description": "PriorityOrder defines the workload priority order for the \"priority\" strategy.\nListed workloads also keep their own prompt names (unlisted workloads'\nprompts stay backend-prefixed).", "items": { "type": "string" }, @@ -939,6 +939,12 @@ "default": 1024, "description": "MaxDataSize limits the size of request/response data included in audit logs (in bytes).", "type": "integer" + }, + "maxDelegationDepth": { + "default": 10, + "description": "MaxDelegationDepth caps how many nested RFC 8693 \"act\" entries are\nrecorded in an audit event's delegation chain. Deeper chains are\ntruncated (marked with truncated=true). Defaults to 10 when unset.", + "minimum": 1, + "type": "integer" } }, "type": "object" @@ -1327,6 +1333,10 @@ "description": "Audience is the required token audience.", "type": "string" }, + "caBundlePath": { + "description": "CABundlePath is the absolute file path to a PEM-encoded CA certificate bundle\nused when the OIDC middleware performs HTTPS requests to the issuer\n(OIDC discovery, JWKS fetch, token introspection). When set, the CA bundle\nat this path is added to the trust store used for verifying the issuer's\nTLS certificate. Typically populated by the Kubernetes operator from\nMCPOIDCConfig.spec.inline.caBundleRef (ConfigMap) or from the in-cluster\nservice-account CA when using Kubernetes service-account auth.", + "type": "string" + }, "clientId": { "description": "ClientID is the OAuth client ID.", "type": "string" @@ -1501,7 +1511,7 @@ "type": "object" }, "optimizer": { - "description": "Optimizer configures the MCP optimizer for context optimization on large toolsets.\nWhen enabled, vMCP exposes only find_tool and call_tool operations to clients\ninstead of all backend tools directly. This reduces token usage by allowing\nLLMs to discover relevant tools on demand rather than receiving all tool definitions.", + "description": "Optimizer configures the MCP optimizer for context optimization on large toolsets.\nWhen enabled, vMCP exposes only find_tool and call_tool operations to clients\ninstead of all backend tools directly. This reduces token usage by allowing\nLLMs to discover relevant tools on demand rather than receiving all tool definitions.\nEnabling the optimizer currently pins this instance to MCP 2025-11-25: the\nfind_tool/call_tool meta-tools are session-scoped, so Modern-capable (2026-07-28)\nclients are negotiated down to the Legacy revision (see\npkg/vmcp/server/modern_gate.go; Modern parity is tracked in stacklok/toolhive#6089).", "properties": { "embeddingHeaders": { "additionalProperties": { @@ -2912,6 +2922,10 @@ "format": "date-time", "type": "string" }, + "mcpRevision": { + "description": "MCPRevision is the backend's negotiated MCP protocol revision\n(\"2026-07-28\" or \"2025-11-25\"). Empty when the backend has not been probed.", + "type": "string" + }, "message": { "description": "Message provides additional information about the backend status", "type": "string" From d43a13811bc8405dca18f4d8c9201ad8a8885cf7 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 19:54:36 +0000 Subject: [PATCH 3/8] Add v0.41.0 hand-written doc updates Cover the v0.41.0 changes that need prose: rate-limit JSON-RPC code change from -32029 to 429, MCP 2026-07-28 revision, operator storage version migrator default and namespace opt-out, opt-in image-discovery Deployment, --build-with on uvx builds, --strict-protocol-validation, Envoy egress backend, reproducible project skills workflow, embedded authorization server RFC 8693 token exchange with delegation audit, and Cedar multi-valued claim normalization. Co-Authored-By: Claude Opus 4.7 --- docs/toolhive/concepts/cedar-policies.mdx | 4 + .../concepts/embedded-auth-server.mdx | 33 +++++++ docs/toolhive/concepts/mcp-primer.mdx | 11 ++- docs/toolhive/concepts/skills.mdx | 20 ++++ docs/toolhive/guides-cli/build-containers.mdx | 31 ++++++ .../toolhive/guides-cli/network-isolation.mdx | 23 +++++ docs/toolhive/guides-cli/run-mcp-servers.mdx | 32 ++++++ .../toolhive/guides-cli/skills-management.mdx | 98 +++++++++++++++++++ docs/toolhive/guides-k8s/deploy-operator.mdx | 62 ++++++++++++ docs/toolhive/guides-k8s/rate-limiting.mdx | 12 ++- .../reference/authz-policy-reference.mdx | 53 ++++++++++ 11 files changed, 373 insertions(+), 6 deletions(-) diff --git a/docs/toolhive/concepts/cedar-policies.mdx b/docs/toolhive/concepts/cedar-policies.mdx index a132b9f7..355b821a 100644 --- a/docs/toolhive/concepts/cedar-policies.mdx +++ b/docs/toolhive/concepts/cedar-policies.mdx @@ -125,6 +125,10 @@ cedar: separate from group claims. Use this when your identity provider provides roles in a different claim than groups (for example, Entra ID `roles` claim). If not set, roles are extracted from the same claims as groups. + - `multi_valued_claims`: Optional list of JWT claim names to normalize as + OAuth scope-shaped values, unifying space-delimited and array shapes. See + [Multi-valued claim normalization](../reference/authz-policy-reference.mdx#multi-valued-claim-normalization) + in the policy reference for the exposed attributes and migration notes. ## Writing effective policies diff --git a/docs/toolhive/concepts/embedded-auth-server.mdx b/docs/toolhive/concepts/embedded-auth-server.mdx index d02edbc9..eb8ffebb 100644 --- a/docs/toolhive/concepts/embedded-auth-server.mdx +++ b/docs/toolhive/concepts/embedded-auth-server.mdx @@ -126,6 +126,39 @@ client's credential headers (`Authorization`, `Cookie`, and `Proxy-Authorization`) instead of swapping them for an upstream token, so the backend receives an unauthenticated request. +## Delegated tokens via RFC 8693 token exchange + +Starting in v0.41.0, the embedded authorization server's token endpoint accepts +[RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange +requests. A client that already holds a ToolHive-issued JWT can present it as a +`subject_token` and receive a new token, minted with a different audience or a +narrower scope set, that acts on behalf of the same user. An agent framework +uses this pattern when it needs to call several downstream services under a +single user's identity without re-prompting the user. + +The token endpoint uses the grant type +`urn:ietf:params:oauth:grant-type:token-exchange`. Only confidential clients +that were registered with the token-exchange grant may call it; public clients +are refused. The exchanged token's audience is bounded by the subject token's +own audience so a compromised client cannot broaden its reach. + +### Delegation chain in audit logs + +When the exchange succeeds, ToolHive mints an `act` claim on the new token +recording which client is acting for the user. If the subject token already +carried a prior `act`, it is nested inside the new one, giving an auditable +delegation chain rather than dropping the earlier hop. The chain depth is capped +at 10 hops; exchanges that would exceed the cap are refused. + +Audit events for delegated calls carry a `delegation` object with the full +`chain` (each hop's actor client ID), so "agent X acting for Alice" is +distinguishable from "Alice directly" in the audit log. Non-delegated tokens +(plain user tokens with no `act` claim) omit the `delegation` field entirely. + +Cedar policies can also read the `act` claim through the standard +`claim_`-prefixed attributes; see +[Principal attributes](../reference/authz-policy-reference.mdx#principal-attributes). + ## Automatic token refresh Upstream access tokens expire independently of the ToolHive JWT lifespan. When diff --git a/docs/toolhive/concepts/mcp-primer.mdx b/docs/toolhive/concepts/mcp-primer.mdx index 2f57495e..e0c53899 100644 --- a/docs/toolhive/concepts/mcp-primer.mdx +++ b/docs/toolhive/concepts/mcp-primer.mdx @@ -160,10 +160,13 @@ combines the official registry with the curated ToolHive catalog. ## Where MCP is headed -The spec uses dated revisions (2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25) -rather than semver, with the `MCP-Protocol-Version` header allowing clients and -servers to negotiate compatibility. The core protocol is deliberately small; new -capabilities arrive as additive extensions, including a separate +The spec uses dated revisions (2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25, +2026-07-28) rather than semver, with the `MCP-Protocol-Version` header allowing +clients and servers to negotiate compatibility. The 2026-07-28 revision adds a +stateless variant that drops the `initialize` handshake and carries per-request +protocol metadata in `_meta`, sitting alongside the session-based 2025-11-25 +revision that most clients use today. The core protocol is deliberately small; +new capabilities arrive as additive extensions, including a separate [authorization extensions](https://github.com/modelcontextprotocol/ext-auth) track for advanced auth scenarios. diff --git a/docs/toolhive/concepts/skills.mdx b/docs/toolhive/concepts/skills.mdx index 06a126c5..0c85d286 100644 --- a/docs/toolhive/concepts/skills.mdx +++ b/docs/toolhive/concepts/skills.mdx @@ -148,6 +148,26 @@ Skills can be distributed as: - **Registry entries**: Published to a ToolHive Registry Server for centralized discovery and installation by name +## Reproducible project-scope installs + +Project-scope skill installs can be pinned in a `toolhive.lock.yaml` file at the +project root, so every team member and every CI run ends up with the same skill +content. Each entry records the skill's resolved reference, digest, content +digest, and (when available) Sigstore provenance. Commit the lock file to the +repository like `package-lock.json` or `go.sum`. + +Two experimental commands operate on the lock file: + +- `thv skill sync` restores a project's installs to match `toolhive.lock.yaml` + and, with `--check`, reports drift for CI without changing anything. +- `thv skill upgrade` re-resolves pinned entries to newer content in a + controlled way, with a preview mode and a freshness gate for CI. + +The lock file feature is experimental in v0.41.0 and requires +`TOOLHIVE_SKILLS_LOCK_ENABLED=true` on the ToolHive API server process. For the +full workflow, flag reference, and typed exit codes, see +[Pin a project's skills for reproducible installs](../guides-cli/skills-management.mdx#pin-a-projects-skills-for-reproducible-installs). + ## Next steps - [Manage agent skills in the ToolHive UI](../guides-ui/skills.mdx) diff --git a/docs/toolhive/guides-cli/build-containers.mdx b/docs/toolhive/guides-cli/build-containers.mdx index 47896f98..cbef994b 100644 --- a/docs/toolhive/guides-cli/build-containers.mdx +++ b/docs/toolhive/guides-cli/build-containers.mdx @@ -206,6 +206,37 @@ You can include multiple build-time arguments as needed: thv build uvx://my-package -- --transport stdio --log-level info ``` +## Constrain build-time dependencies + +Some Python MCP servers pull in transitive dependencies whose newer versions +break the server. Use the `--build-with` flag on `uvx://` builds to pin those +dependencies at build time. ToolHive passes each `--build-with` value through to +`uv tool install --with` as a [PEP 508](https://peps.python.org/pep-0508/) +specifier, so you can pin an exact version, cap a major version, or express any +other valid specifier: + +```bash +# Cap the mcp package at 1.x while installing an MCP server +thv build --build-with 'mcp<2' uvx://mcp-server-git + +# Combine multiple constraints +thv build \ + --build-with 'mcp<2' \ + --build-with 'anyio>=4' \ + uvx://mcp-server-example +``` + +The same flag is available on [`thv run`](./run-mcp-servers.mdx) when you're +running directly from a protocol scheme instead of pre-building. + +:::info[uvx only] + +`--build-with` is only supported for `uvx://` protocol scheme builds. Passing it +to an `npx://` or `go://` build fails with an explicit error rather than +silently ignoring the constraint. + +::: + ## Dockerfile generation Use the `--dry-run` flag to generate the Dockerfile without building the image: diff --git a/docs/toolhive/guides-cli/network-isolation.mdx b/docs/toolhive/guides-cli/network-isolation.mdx index 677c101a..27e7828d 100644 --- a/docs/toolhive/guides-cli/network-isolation.mdx +++ b/docs/toolhive/guides-cli/network-isolation.mdx @@ -205,6 +205,29 @@ thv run --isolate-network=false The container's own network namespace still isolates it from the host; only ToolHive's allowlist enforcement is disabled. +## Choose an egress proxy backend + +By default, ToolHive uses Squid for egress filtering. Starting in v0.41.0, +ToolHive also supports an Envoy backend that consolidates egress and ingress +into a single sidecar and translates the permission profile's `AllowHost` and +`AllowPort` rules into Envoy RBAC policies. Squid remains the default. + +Set the `TOOLHIVE_NETWORK_PROXY` environment variable before running `thv run` +(or `thv serve` if you use the API server) to select the backend: + +```bash +# Default: Squid backend +export TOOLHIVE_NETWORK_PROXY=squid # or leave unset + +# Opt-in: Envoy backend +export TOOLHIVE_NETWORK_PROXY=envoy +thv run +``` + +Any other value causes ToolHive to exit at startup with an error. Both backends +enforce the same permission profile semantics, so you don't need to change your +permission profile to switch backends. + ## Interaction with `--network host` and `--network none` Network isolation is a bridge-network construct: the egress, DNS, and ingress diff --git a/docs/toolhive/guides-cli/run-mcp-servers.mdx b/docs/toolhive/guides-cli/run-mcp-servers.mdx index bb36a6b0..b4549120 100644 --- a/docs/toolhive/guides-cli/run-mcp-servers.mdx +++ b/docs/toolhive/guides-cli/run-mcp-servers.mdx @@ -297,9 +297,41 @@ thv run --runtime-add-package git --runtime-add-package ca-certificates \ uvx://mcp-server-git ``` +To constrain build-time Python dependencies for `uvx://` runs, use +`--build-with` with a [PEP 508](https://peps.python.org/pep-0508/) specifier. +Each value is passed through to `uv tool install --with`, so you can pin exact +versions or cap majors: + +```bash +thv run --build-with 'mcp<2' uvx://mcp-server-git +``` + +`--build-with` is only supported for `uvx://` builds; passing it to `npx://` or +`go://` fails with an explicit error. To pre-build the image with the same +constraints, pass identical flags to +[`thv build`](./build-containers.mdx#constrain-build-time-dependencies). + These flags apply only to protocol-scheme runs, since that's when ToolHive builds the image. +### Reject unknown MCP protocol versions + +By default, the streamable-HTTP proxy accepts any value for the +`MCP-Protocol-Version` header (an absent header is also accepted). To reject +clients that send an unknown or unsupported revision, add the +`--strict-protocol-validation` flag: + +```bash +thv run --transport streamable-http --strict-protocol-validation +``` + +Requests whose `MCP-Protocol-Version` header is not one of the revisions this +ToolHive build recognizes are refused with HTTP 400. Requests with no header are +still accepted, so lenient clients continue to work. + +Use this flag when you want to enforce a specific revision set at the proxy, for +example to keep a fleet on a known-good protocol version during a rollout. + ### Configure network transport When you run custom MCP servers using the SSE (`--transport sse`) or Streamable diff --git a/docs/toolhive/guides-cli/skills-management.mdx b/docs/toolhive/guides-cli/skills-management.mdx index 3df6f137..6d935e44 100644 --- a/docs/toolhive/guides-cli/skills-management.mdx +++ b/docs/toolhive/guides-cli/skills-management.mdx @@ -320,6 +320,102 @@ authenticated before pushing. ::: +## Pin a project's skills for reproducible installs + +:::warning[Experimental in v0.41.0] + +The skills lock file, `thv skill sync`, and `thv skill upgrade` are experimental +in v0.41.0. Set `TOOLHIVE_SKILLS_LOCK_ENABLED=true` on the process running the +ToolHive API server (either the `thv serve` shell or the ToolHive desktop app) +before using any lock-file command. Without it, sync and upgrade fail with: + +```text +skills lock file support is experimental; set TOOLHIVE_SKILLS_LOCK_ENABLED=true to use it +``` + +Behavior, flag names, and file format may change before the feature stabilizes. + +::: + +If you install project-scoped skills across a team or a CI environment, you +usually want everyone (and every build) to end up with exactly the same skill +content. ToolHive records project-scope installs in a `toolhive.lock.yaml` file +at the project root; `thv skill sync` restores that pinned set on another +machine, and `thv skill upgrade` re-resolves pinned entries to newer content in +a controlled way. + +The lock file sits next to `.git` in the project root and pins each skill's +resolved reference, digest, content digest, and (when available) Sigstore +provenance. Commit it to the repository like `package-lock.json` or `go.sum`. + +### Restore pinned skills with `thv skill sync` + +`thv skill sync` reads `toolhive.lock.yaml` from the project root, compares it +to what is currently installed, and reinstalls anything that's missing or has +drifted, restoring each entry to its pinned digest: + +```bash +export TOOLHIVE_SKILLS_LOCK_ENABLED=true +thv skill sync --project-root /path/to/project +``` + +Because skill content is a set of instructions that AI agents follow, sync +prompts for confirmation before installing anything. In CI, pass `--yes` to skip +the prompt (required when stdin isn't a terminal): + +```bash +thv skill sync --project-root . --yes +``` + +A few flags are worth knowing for CI use: + +- `--check` reports drift without installing, writing, or removing anything. Use + this as a freshness gate. +- `--adopt` writes lock entries for existing project-scope installs that aren't + tracked yet; use it when onboarding an existing project. +- `--prune` removes installs no longer present in the lock file. +- `--clients ` restricts sync to specific client apps (for example, + `claude-code,cursor`), or `all` for every available client. + +### Upgrade pinned skills with `thv skill upgrade` + +`thv skill upgrade` re-resolves lock entries and installs newer content where +available. Immutable references (an OCI digest or a full git commit hash) are +reported as not-upgradable because there is nothing newer to resolve to. + +```bash +thv skill upgrade --project-root /path/to/project +``` + +Preview a plan without persisting anything (OCI sources are still fetched into +the local artifact store so digests can be compared): + +```bash +thv skill upgrade --preview +``` + +`--fail-on-changes` evaluates the same plan but never installs; use it as a CI +freshness gate that fails when the pinned set is not up to date. +`--allow-ref-change` permits the resolved reference itself to change (for +example, when a registry entry has been repointed at a different repository); +without it, ref changes are refused for safety. + +### Typed exit codes for CI + +Both `thv skill sync` and `thv skill upgrade` use typed exit codes so CI +pipelines can distinguish outcomes: + +| Exit code | Meaning | +| --------- | ------------------------------------------------------------------------------------------------------- | +| `0` | Success | +| `1` | Command usage or setup error (standard Cobra/CLI default) | +| `2` | Check failure: `sync --check` or `upgrade --fail-on-changes` found drift; nothing was applied | +| `3` | Partial failure: some (not all) targeted skills failed during sync or upgrade | +| `4` | Policy rejection: refused non-interactively without `--yes`, or ref change without `--allow-ref-change` | + +When multiple failures apply, partial failure (`3`) takes precedence over check +failure (`2`), which takes precedence over policy rejection (`4`). + ## List and remove locally-built skill artifacts After building skills locally, you can view and manage the artifacts stored in @@ -377,6 +473,8 @@ pointing to that digest are removed. - [Manage agent skills in the ToolHive UI](../guides-ui/skills.mdx) to browse, install, and build skills without leaving the app - [`thv skill` command reference](../reference/cli/thv_skill.md) +- [`thv skill sync` command reference](../reference/cli/thv_skill_sync.md) +- [`thv skill upgrade` command reference](../reference/cli/thv_skill_upgrade.md) - [`thv serve` command reference](../reference/cli/thv_serve.md) - [Agent Skills specification](https://agentskills.io/specification) diff --git a/docs/toolhive/guides-k8s/deploy-operator.mdx b/docs/toolhive/guides-k8s/deploy-operator.mdx index 7e298b7d..5d3beb2b 100644 --- a/docs/toolhive/guides-k8s/deploy-operator.mdx +++ b/docs/toolhive/guides-k8s/deploy-operator.mdx @@ -436,6 +436,68 @@ You can switch between cluster mode and namespace mode by updating the `values.yaml` file and reapplying the Helm chart as shown above. Migration in both directions is supported. +### Storage version migrator (namespace-mode opt-out) + +Starting in v0.41.0, the operator chart enables the storage version migrator +controller by default. This controller trims deprecated API versions from the +`status.storedVersions` list on ToolHive CRDs so that a future release can drop +those versions cleanly. It watches cluster-scoped CustomResourceDefinitions and +re-stores resources across all namespaces, which a namespace-scoped operator +cannot do. + +Cluster-scoped installs (the default) get the migrator automatically. The chart +doesn't create new pods or RBAC objects; the existing operator container gains +the controller after it restarts. + +**Namespace-scoped installs must opt out.** `helm install` or `helm upgrade` +fails at render time with: + +```text +operator.features.storageVersionMigrator requires operator.rbac.scope=cluster +``` + +Add the opt-out to your `values.yaml`: + +```yaml title="values.yaml" +operator: + rbac: + scope: 'namespace' + # highlight-start + features: + storageVersionMigrator: false + # highlight-end +``` + +Because namespace-scoped installs cannot run the migrator, plan to clean CRD +`status.storedVersions` by other means (for example, a one-off run of +[kube-storage-version-migrator](https://github.com/kubernetes-sigs/kube-storage-version-migrator)) +before any future release drops a deprecated CRD version. + +### Static image discovery for air-gapped installs + +The operator injects three runtime images (the ToolHive runner, the vMCP image, +and the Registry API image) into workloads at runtime, so they never appear in +the operator Deployment manifest. In air-gapped environments where +image-mirroring tooling scans manifests statically, these references are +invisible. + +Set `operator.imageDiscovery.enabled: true` to render an +`-image-discovery` Deployment with `replicas: 0`. The Deployment exists +only to expose the three image references behind `image:` keys so static +scanners can find them; because `replicas` is zero, no pods schedule and the +container runtime pulls no images. + +```yaml title="values.yaml" +operator: + # highlight-start + imageDiscovery: + enabled: true + # Optional: set resource requests/limits to satisfy LimitRange or + # policy controllers even on a zero-replica Deployment. + resources: {} + # highlight-end +``` + ## Check operator status To verify the operator is working correctly: diff --git a/docs/toolhive/guides-k8s/rate-limiting.mdx b/docs/toolhive/guides-k8s/rate-limiting.mdx index 0b4fcadb..dac958c5 100644 --- a/docs/toolhive/guides-k8s/rate-limiting.mdx +++ b/docs/toolhive/guides-k8s/rate-limiting.mdx @@ -51,8 +51,16 @@ unconditionally. When a request is rejected, the proxy returns: - **HTTP 429** with a `Retry-After` header (seconds until a token is available) -- A **JSON-RPC error** with code `-32029` and `retryAfterSeconds` in the error - data +- A **JSON-RPC error** with code `429` and `retryAfterSeconds` in the error data + +:::note[Error code change in v0.41.0] + +The JSON-RPC `error.code` for rate limiting moved from `-32029` to `429` in +ToolHive v0.41.0 to avoid a range reserved by the MCP 2026-07-28 spec. The HTTP +`429` status, the `Retry-After` header, and the `data.retryAfterSeconds` field +are unchanged; branch on those values for your backoff logic. + +::: If Redis is unreachable, rate limiting **fails open** and all requests are allowed through. diff --git a/docs/toolhive/reference/authz-policy-reference.mdx b/docs/toolhive/reference/authz-policy-reference.mdx index d55a780d..b287607d 100644 --- a/docs/toolhive/reference/authz-policy-reference.mdx +++ b/docs/toolhive/reference/authz-policy-reference.mdx @@ -121,6 +121,59 @@ subject of an [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) delegation `act` claim. Nesting deeper than 10 levels is dropped rather than converted, since claim values can originate from an unverified upstream token. +### Multi-valued claim normalization + +OAuth scope claims can arrive in two shapes depending on the identity provider: +a space-delimited string (`"read write admin"`) or a JSON array +(`["read", "write", "admin"]`). Without normalization, Cedar policies that match +on scope values have to handle both shapes, or fail closed when the shape +changes. + +Starting in v0.41.0, the Cedar authorizer config accepts a `multi_valued_claims` +list. Naming a claim in this list changes how the authorizer exposes it: a new +set-shaped `claimset_` attribute becomes available, and the existing +`claim_` attribute is normalized to a canonical space-delimited string: + +| Attribute | Cedar type | How to use | +| ----------------- | -------------- | --------------------------------------------------------------------- | +| `claimset_` | Set of Strings | Exact-element membership: `.contains`, `.containsAll`, `.containsAny` | +| `claim_` | String | Canonical space-delimited form, for `like` or `==` | + +```yaml title="cedar-config.yaml" +version: 1 +type: cedarv1 +cedar: + # highlight-next-line + multi_valued_claims: ['scope', 'scp'] + policies: + - | + permit( + principal, + action == Action::"call_tool", + resource + ) when { + principal.claimset_scope.contains("mcp:tools") + }; +``` + +Only list claims whose element values contain no spaces (for example, OAuth +scopes per +[RFC 6749 §3.3](https://datatracker.ietf.org/doc/html/rfc6749#section-3.3) such +as `scope` and `scp`). Don't list group or role claims, or any claim whose +values can contain spaces; their internal spaces would be mis-tokenized into +separate elements. + +:::warning[Migration hazard for existing `like` policies] + +Adding an array-shaped claim to `multi_valued_claims` changes its `claim_` +attribute from a Cedar `Set` to a `String`. If an existing policy did +`principal.claim_scope like "*mcp:tools*"` against the same claim, it will start +matching more permissively (substring, not exact element). Audit `like` policies +against any claim before opting it in, and prefer +`claimset_.contains(...)` for exact-element membership. + +::: + ## Resource attributes Resource attributes vary depending on the type of MCP operation. Each operation From 26fed2fc5a1c1e236ce3f9fb9eab4adf5039f511 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 20:01:29 +0000 Subject: [PATCH 4/8] Apply editorial review to v0.41.0 doc updates - Move air-gapped image discovery out of deployment-modes section, into the operator customization section where the other image and Helm values live. The parent section is scoped to cluster vs. namespace mode; static image discovery is orthogonal. - Rephrase the delegated-token intro to address the reader directly rather than starting with "An agent framework uses ..." - Name the reserved JSON-RPC code range in the rate-limit change note. - Reword the cedar multi_valued_claims bullet to drop the jargon ("scope-shaped values") and lead with an example. - Promote the --build-with "uvx only" admonition to a warning; passing it to npx/go fails. Co-Authored-By: Claude Opus 4.7 --- docs/toolhive/concepts/cedar-policies.mdx | 6 ++- .../concepts/embedded-auth-server.mdx | 6 +-- docs/toolhive/guides-cli/build-containers.mdx | 2 +- docs/toolhive/guides-k8s/deploy-operator.mdx | 50 +++++++++---------- docs/toolhive/guides-k8s/rate-limiting.mdx | 7 +-- 5 files changed, 37 insertions(+), 34 deletions(-) diff --git a/docs/toolhive/concepts/cedar-policies.mdx b/docs/toolhive/concepts/cedar-policies.mdx index 355b821a..cdfe25cb 100644 --- a/docs/toolhive/concepts/cedar-policies.mdx +++ b/docs/toolhive/concepts/cedar-policies.mdx @@ -125,8 +125,10 @@ cedar: separate from group claims. Use this when your identity provider provides roles in a different claim than groups (for example, Entra ID `roles` claim). If not set, roles are extracted from the same claims as groups. - - `multi_valued_claims`: Optional list of JWT claim names to normalize as - OAuth scope-shaped values, unifying space-delimited and array shapes. See + - `multi_valued_claims`: Optional list of JWT claim names (for example, + `scope`, `scp`) to normalize into a canonical form so policies match the + same way whether the claim arrives as a space-delimited string or a JSON + array. See [Multi-valued claim normalization](../reference/authz-policy-reference.mdx#multi-valued-claim-normalization) in the policy reference for the exposed attributes and migration notes. diff --git a/docs/toolhive/concepts/embedded-auth-server.mdx b/docs/toolhive/concepts/embedded-auth-server.mdx index eb8ffebb..16f1eee3 100644 --- a/docs/toolhive/concepts/embedded-auth-server.mdx +++ b/docs/toolhive/concepts/embedded-auth-server.mdx @@ -132,9 +132,9 @@ Starting in v0.41.0, the embedded authorization server's token endpoint accepts [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange requests. A client that already holds a ToolHive-issued JWT can present it as a `subject_token` and receive a new token, minted with a different audience or a -narrower scope set, that acts on behalf of the same user. An agent framework -uses this pattern when it needs to call several downstream services under a -single user's identity without re-prompting the user. +narrower scope set, that acts on behalf of the same user. Use this pattern when +an agent framework needs to call several downstream services under a single +user's identity without re-prompting the user. The token endpoint uses the grant type `urn:ietf:params:oauth:grant-type:token-exchange`. Only confidential clients diff --git a/docs/toolhive/guides-cli/build-containers.mdx b/docs/toolhive/guides-cli/build-containers.mdx index cbef994b..c631eb3b 100644 --- a/docs/toolhive/guides-cli/build-containers.mdx +++ b/docs/toolhive/guides-cli/build-containers.mdx @@ -229,7 +229,7 @@ thv build \ The same flag is available on [`thv run`](./run-mcp-servers.mdx) when you're running directly from a protocol scheme instead of pre-building. -:::info[uvx only] +:::warning[uvx only] `--build-with` is only supported for `uvx://` protocol scheme builds. Passing it to an `npx://` or `go://` build fails with an explicit error rather than diff --git a/docs/toolhive/guides-k8s/deploy-operator.mdx b/docs/toolhive/guides-k8s/deploy-operator.mdx index 5d3beb2b..4e421045 100644 --- a/docs/toolhive/guides-k8s/deploy-operator.mdx +++ b/docs/toolhive/guides-k8s/deploy-operator.mdx @@ -205,6 +205,31 @@ The chart also exposes `operator.imagePullSecrets`, which controls only the operator's own pod. Use it when the operator image itself is in a private registry; use `defaultImagePullSecrets` for the workloads the operator manages. +### Static image discovery for air-gapped installs + +The operator injects three runtime images (the ToolHive runner, the vMCP image, +and the Registry API image) into workloads at runtime, so they never appear in +the operator Deployment manifest. In air-gapped environments where +image-mirroring tooling scans manifests statically, these references are +invisible. + +Starting in v0.41.0, set `operator.imageDiscovery.enabled: true` to render an +`-image-discovery` Deployment with `replicas: 0`. The Deployment exists +only to expose the three image references behind `image:` keys so static +scanners can find them; because `replicas` is zero, no pods schedule and the +container runtime pulls no images. + +```yaml title="values.yaml" +operator: + # highlight-start + imageDiscovery: + enabled: true + # Optional: set resource requests/limits to satisfy LimitRange or + # policy controllers even on a zero-replica Deployment. + resources: {} + # highlight-end +``` + ### Scale the operator with autoscaling The operator runs a single replica by default. For high availability, run more @@ -473,31 +498,6 @@ Because namespace-scoped installs cannot run the migrator, plan to clean CRD [kube-storage-version-migrator](https://github.com/kubernetes-sigs/kube-storage-version-migrator)) before any future release drops a deprecated CRD version. -### Static image discovery for air-gapped installs - -The operator injects three runtime images (the ToolHive runner, the vMCP image, -and the Registry API image) into workloads at runtime, so they never appear in -the operator Deployment manifest. In air-gapped environments where -image-mirroring tooling scans manifests statically, these references are -invisible. - -Set `operator.imageDiscovery.enabled: true` to render an -`-image-discovery` Deployment with `replicas: 0`. The Deployment exists -only to expose the three image references behind `image:` keys so static -scanners can find them; because `replicas` is zero, no pods schedule and the -container runtime pulls no images. - -```yaml title="values.yaml" -operator: - # highlight-start - imageDiscovery: - enabled: true - # Optional: set resource requests/limits to satisfy LimitRange or - # policy controllers even on a zero-replica Deployment. - resources: {} - # highlight-end -``` - ## Check operator status To verify the operator is working correctly: diff --git a/docs/toolhive/guides-k8s/rate-limiting.mdx b/docs/toolhive/guides-k8s/rate-limiting.mdx index dac958c5..cf993736 100644 --- a/docs/toolhive/guides-k8s/rate-limiting.mdx +++ b/docs/toolhive/guides-k8s/rate-limiting.mdx @@ -56,9 +56,10 @@ When a request is rejected, the proxy returns: :::note[Error code change in v0.41.0] The JSON-RPC `error.code` for rate limiting moved from `-32029` to `429` in -ToolHive v0.41.0 to avoid a range reserved by the MCP 2026-07-28 spec. The HTTP -`429` status, the `Retry-After` header, and the `data.retryAfterSeconds` field -are unchanged; branch on those values for your backoff logic. +ToolHive v0.41.0 because the MCP 2026-07-28 spec reserves the `-32020` to +`-32099` JSON-RPC code range for spec use. The HTTP `429` status, the +`Retry-After` header, and the `data.retryAfterSeconds` field are unchanged; +branch on those values for your backoff logic. ::: From 03e91c930d506db423c95f5339374794dd9ba929 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 29 Jul 2026 20:32:42 +0200 Subject: [PATCH 5/8] Correct RFC 8693 delegation docs The v0.41.0 doc updates described the embedded authorization server's token endpoint as accepting RFC 8693 token exchange requests. Verified against the v0.41.0 tag (toolhive d72230424), that isn't reachable by users: the grant dispatch, confidential-client check, and audience bounding are all implemented, but the only path that registers clients (DCR) creates public clients with an authorization_code/refresh_token allowlist, and the grant isn't advertised in discovery metadata. The only clients registered for the grant are in tests, injected via a test-only storage backdoor. Drop the claim rather than document a feature nobody can enable. Reframe the section around what does work: ToolHive reads the act claim from any JWT it validates, so delegation audit and Cedar policies apply to tokens minted by an external IdP performing its own exchange. Also fix two errors in the same section: - Delegation audit was described as happening at token issuance. The token-exchange handler emits no audit events; all three producers are on the consumption path, firing per MCP request, per SSE connection, and per vMCP workflow step. Each hop is independently auditable. - The 10-hop cap was described as refusing exchanges, which applied to the removed issuance path. On the consumption path, over-deep chains are truncated and flagged. Add the introspection caveat, which is a silent failure mode: with opaque token introspection configured, act never reaches the audit and authorization layers, because the fixed claim struct's catch-all field is tagged json:"-" and never populates. Note in the policy reference that claim_-prefixed attributes are available on both principal and context, which explains why that page reads context.claim_act.sub under "Principal attributes". Co-Authored-By: Claude Opus 5 --- .../concepts/embedded-auth-server.mdx | 88 ++++++++++++------- .../reference/authz-policy-reference.mdx | 4 + 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/docs/toolhive/concepts/embedded-auth-server.mdx b/docs/toolhive/concepts/embedded-auth-server.mdx index 16f1eee3..0a0e9970 100644 --- a/docs/toolhive/concepts/embedded-auth-server.mdx +++ b/docs/toolhive/concepts/embedded-auth-server.mdx @@ -126,38 +126,62 @@ client's credential headers (`Authorization`, `Cookie`, and `Proxy-Authorization`) instead of swapping them for an upstream token, so the backend receives an unauthenticated request. -## Delegated tokens via RFC 8693 token exchange - -Starting in v0.41.0, the embedded authorization server's token endpoint accepts -[RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange -requests. A client that already holds a ToolHive-issued JWT can present it as a -`subject_token` and receive a new token, minted with a different audience or a -narrower scope set, that acts on behalf of the same user. Use this pattern when -an agent framework needs to call several downstream services under a single -user's identity without re-prompting the user. - -The token endpoint uses the grant type -`urn:ietf:params:oauth:grant-type:token-exchange`. Only confidential clients -that were registered with the token-exchange grant may call it; public clients -are refused. The exchanged token's audience is bounded by the subject token's -own audience so a compromised client cannot broaden its reach. - -### Delegation chain in audit logs - -When the exchange succeeds, ToolHive mints an `act` claim on the new token -recording which client is acting for the user. If the subject token already -carried a prior `act`, it is nested inside the new one, giving an auditable -delegation chain rather than dropping the earlier hop. The chain depth is capped -at 10 hops; exchanges that would exceed the cap are refused. - -Audit events for delegated calls carry a `delegation` object with the full -`chain` (each hop's actor client ID), so "agent X acting for Alice" is -distinguishable from "Alice directly" in the audit log. Non-delegated tokens -(plain user tokens with no `act` claim) omit the `delegation` field entirely. - -Cedar policies can also read the `act` claim through the standard -`claim_`-prefixed attributes; see -[Principal attributes](../reference/authz-policy-reference.mdx#principal-attributes). +## Delegated identities and the `act` claim + +When a request arrives with a token that acts on behalf of a user rather than +representing that user directly, +[RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) records the acting +party in an `act` claim. ToolHive reads this claim during token validation, so +audit logs and Cedar policies can distinguish "agent X acting for Alice" from +"Alice directly." + +ToolHive reads `act` from any JWT it validates, regardless of which +authorization server minted the token. If your identity provider performs its +own token exchange and issues tokens carrying `act`, the delegation chain is +picked up with no extra configuration. + +:::note + +Delegation data is only available when ToolHive validates the token as a JWT +using JWKS. If you configure opaque token introspection instead, claims outside +the standard introspection response (including `act`) don't reach the audit and +authorization layers. + +::: + +### Delegation chains in audit logs + +Delegation is recorded on every call made with a delegated token, not once when +the token is minted. Each audited MCP request, each SSE connection, and each +vMCP workflow step carries a `delegation` object holding the full chain, so +every hop's activity is independently traceable. + +Each entry in `chain` records the acting party's issuer and subject, ordered +with the most recent actor first. Chains deeper than 10 hops are truncated and +flagged rather than rejected. + +Tokens with no `act` claim omit the `delegation` field entirely. A token that +asserts a delegation ToolHive can't parse is recorded with a malformed flag +instead of being silently treated as non-delegated. + +### Reading the `act` claim in Cedar policies + +The `act` claim is converted to a nested Cedar record under the standard +`claim_` prefix, and is available as both a principal and a context attribute: + +```text +permit( + principal, + action == Action::"call_tool", + resource +) when { + principal.claim_act.sub == "agent-orchestrator" +}; +``` + +Claims nested deeper than 10 levels are dropped rather than converted. See +[Principal attributes](../reference/authz-policy-reference.mdx#principal-attributes) +for the full claim type mapping. ## Automatic token refresh diff --git a/docs/toolhive/reference/authz-policy-reference.mdx b/docs/toolhive/reference/authz-policy-reference.mdx index b287607d..3a1563bc 100644 --- a/docs/toolhive/reference/authz-policy-reference.mdx +++ b/docs/toolhive/reference/authz-policy-reference.mdx @@ -100,6 +100,10 @@ The exact attributes available depend on your identity provider and token configuration. Check your access token's claims to see what's available. Every claim becomes a `claim_`-prefixed attribute automatically. +Every `claim_`-prefixed attribute is available on both the principal and the +context, so `principal.claim_email` and `context.claim_email` read the same +value. Use whichever reads more naturally in your policy. + ::: ### Claim type mapping From e51081a628cbf83f6f4ed3b925d423e699ddb9ac Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 29 Jul 2026 20:48:52 +0200 Subject: [PATCH 6/8] Trim MCP revision note in primer The v0.41.0 doc updates added four lines explaining that the 2026-07-28 spec revision introduces a stateless variant dropping the initialize handshake and carrying protocol metadata in _meta. That's more mechanical detail than a primer needs, and the roadmap paragraph directly below already covers the same theme at the right altitude ("scaling Streamable HTTP statelessly behind load balancers"). Keep the new revision date in the list, drop the explanation. Co-Authored-By: Claude Opus 5 --- docs/toolhive/concepts/mcp-primer.mdx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/toolhive/concepts/mcp-primer.mdx b/docs/toolhive/concepts/mcp-primer.mdx index e0c53899..f662d0f2 100644 --- a/docs/toolhive/concepts/mcp-primer.mdx +++ b/docs/toolhive/concepts/mcp-primer.mdx @@ -162,11 +162,9 @@ combines the official registry with the curated ToolHive catalog. The spec uses dated revisions (2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25, 2026-07-28) rather than semver, with the `MCP-Protocol-Version` header allowing -clients and servers to negotiate compatibility. The 2026-07-28 revision adds a -stateless variant that drops the `initialize` handshake and carries per-request -protocol metadata in `_meta`, sitting alongside the session-based 2025-11-25 -revision that most clients use today. The core protocol is deliberately small; -new capabilities arrive as additive extensions, including a separate +clients and servers to negotiate compatibility. The core protocol is +deliberately small; new capabilities arrive as additive extensions, including a +separate [authorization extensions](https://github.com/modelcontextprotocol/ext-auth) track for advanced auth scenarios. From bb3db9078d80861e94f548aeeb804381122a5187 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 29 Jul 2026 20:48:56 +0200 Subject: [PATCH 7/8] Correct rate limit error code and vMCP shape The JSON-RPC error code for rate limiting is 429 as of ToolHive v0.41.0 (pkg/ratelimit/errors.go), not -32029. Note that vMCP enforces rate limits at a second point, its tool-dispatch layer, which never sets an HTTP 429: the rejection is folded into an HTTP 200 response, so the JSON-RPC error code is the only signal a client has. Readers who detect rate limiting from the HTTP status alone would otherwise miss it entirely, which is the only reason the inner code matters. The v0.41.0 doc updates framed this as an admonition about the code changing from -32029. Left that out: a how-to guide should describe current behavior, and the migration fact belongs in release notes. Worth adding there, since upstream flags it as a wire-visible change. Co-Authored-By: Claude Opus 5 --- docs/toolhive/guides-k8s/rate-limiting.mdx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/docs/toolhive/guides-k8s/rate-limiting.mdx b/docs/toolhive/guides-k8s/rate-limiting.mdx index cf993736..51c9e9bb 100644 --- a/docs/toolhive/guides-k8s/rate-limiting.mdx +++ b/docs/toolhive/guides-k8s/rate-limiting.mdx @@ -53,15 +53,10 @@ When a request is rejected, the proxy returns: - **HTTP 429** with a `Retry-After` header (seconds until a token is available) - A **JSON-RPC error** with code `429` and `retryAfterSeconds` in the error data -:::note[Error code change in v0.41.0] - -The JSON-RPC `error.code` for rate limiting moved from `-32029` to `429` in -ToolHive v0.41.0 because the MCP 2026-07-28 spec reserves the `-32020` to -`-32099` JSON-RPC code range for spec use. The HTTP `429` status, the -`Retry-After` header, and the `data.retryAfterSeconds` field are unchanged; -branch on those values for your backoff logic. - -::: +When vMCP rejects a tool call at its own rate limit, the response is an HTTP 200 +carrying the same JSON-RPC error code, so clients that detect rate limiting from +the HTTP status alone won't see it. Check the JSON-RPC `error.code` to catch +both cases. If Redis is unreachable, rate limiting **fails open** and all requests are allowed through. From 6f5f8e17c2b4891c79cb6088341ac22ff51e721e Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:09:29 +0000 Subject: [PATCH 8/8] Remove experimental skills lock-file docs Drop documentation for the experimental thv skill sync/upgrade commands and the toolhive.lock.yaml lock file until the feature is ready. Removes the guide and concept sections, their cross-links, and the auto-generated CLI reference pages. Co-authored-by: Samuele V <4377202+samuv@users.noreply.github.com> --- docs/toolhive/concepts/skills.mdx | 20 ---- .../toolhive/guides-cli/skills-management.mdx | 98 ------------------- docs/toolhive/reference/cli/thv_skill.md | 2 - docs/toolhive/reference/cli/thv_skill_sync.md | 58 ----------- .../reference/cli/thv_skill_upgrade.md | 62 ------------ 5 files changed, 240 deletions(-) delete mode 100644 docs/toolhive/reference/cli/thv_skill_sync.md delete mode 100644 docs/toolhive/reference/cli/thv_skill_upgrade.md diff --git a/docs/toolhive/concepts/skills.mdx b/docs/toolhive/concepts/skills.mdx index 0c85d286..06a126c5 100644 --- a/docs/toolhive/concepts/skills.mdx +++ b/docs/toolhive/concepts/skills.mdx @@ -148,26 +148,6 @@ Skills can be distributed as: - **Registry entries**: Published to a ToolHive Registry Server for centralized discovery and installation by name -## Reproducible project-scope installs - -Project-scope skill installs can be pinned in a `toolhive.lock.yaml` file at the -project root, so every team member and every CI run ends up with the same skill -content. Each entry records the skill's resolved reference, digest, content -digest, and (when available) Sigstore provenance. Commit the lock file to the -repository like `package-lock.json` or `go.sum`. - -Two experimental commands operate on the lock file: - -- `thv skill sync` restores a project's installs to match `toolhive.lock.yaml` - and, with `--check`, reports drift for CI without changing anything. -- `thv skill upgrade` re-resolves pinned entries to newer content in a - controlled way, with a preview mode and a freshness gate for CI. - -The lock file feature is experimental in v0.41.0 and requires -`TOOLHIVE_SKILLS_LOCK_ENABLED=true` on the ToolHive API server process. For the -full workflow, flag reference, and typed exit codes, see -[Pin a project's skills for reproducible installs](../guides-cli/skills-management.mdx#pin-a-projects-skills-for-reproducible-installs). - ## Next steps - [Manage agent skills in the ToolHive UI](../guides-ui/skills.mdx) diff --git a/docs/toolhive/guides-cli/skills-management.mdx b/docs/toolhive/guides-cli/skills-management.mdx index 6d935e44..3df6f137 100644 --- a/docs/toolhive/guides-cli/skills-management.mdx +++ b/docs/toolhive/guides-cli/skills-management.mdx @@ -320,102 +320,6 @@ authenticated before pushing. ::: -## Pin a project's skills for reproducible installs - -:::warning[Experimental in v0.41.0] - -The skills lock file, `thv skill sync`, and `thv skill upgrade` are experimental -in v0.41.0. Set `TOOLHIVE_SKILLS_LOCK_ENABLED=true` on the process running the -ToolHive API server (either the `thv serve` shell or the ToolHive desktop app) -before using any lock-file command. Without it, sync and upgrade fail with: - -```text -skills lock file support is experimental; set TOOLHIVE_SKILLS_LOCK_ENABLED=true to use it -``` - -Behavior, flag names, and file format may change before the feature stabilizes. - -::: - -If you install project-scoped skills across a team or a CI environment, you -usually want everyone (and every build) to end up with exactly the same skill -content. ToolHive records project-scope installs in a `toolhive.lock.yaml` file -at the project root; `thv skill sync` restores that pinned set on another -machine, and `thv skill upgrade` re-resolves pinned entries to newer content in -a controlled way. - -The lock file sits next to `.git` in the project root and pins each skill's -resolved reference, digest, content digest, and (when available) Sigstore -provenance. Commit it to the repository like `package-lock.json` or `go.sum`. - -### Restore pinned skills with `thv skill sync` - -`thv skill sync` reads `toolhive.lock.yaml` from the project root, compares it -to what is currently installed, and reinstalls anything that's missing or has -drifted, restoring each entry to its pinned digest: - -```bash -export TOOLHIVE_SKILLS_LOCK_ENABLED=true -thv skill sync --project-root /path/to/project -``` - -Because skill content is a set of instructions that AI agents follow, sync -prompts for confirmation before installing anything. In CI, pass `--yes` to skip -the prompt (required when stdin isn't a terminal): - -```bash -thv skill sync --project-root . --yes -``` - -A few flags are worth knowing for CI use: - -- `--check` reports drift without installing, writing, or removing anything. Use - this as a freshness gate. -- `--adopt` writes lock entries for existing project-scope installs that aren't - tracked yet; use it when onboarding an existing project. -- `--prune` removes installs no longer present in the lock file. -- `--clients ` restricts sync to specific client apps (for example, - `claude-code,cursor`), or `all` for every available client. - -### Upgrade pinned skills with `thv skill upgrade` - -`thv skill upgrade` re-resolves lock entries and installs newer content where -available. Immutable references (an OCI digest or a full git commit hash) are -reported as not-upgradable because there is nothing newer to resolve to. - -```bash -thv skill upgrade --project-root /path/to/project -``` - -Preview a plan without persisting anything (OCI sources are still fetched into -the local artifact store so digests can be compared): - -```bash -thv skill upgrade --preview -``` - -`--fail-on-changes` evaluates the same plan but never installs; use it as a CI -freshness gate that fails when the pinned set is not up to date. -`--allow-ref-change` permits the resolved reference itself to change (for -example, when a registry entry has been repointed at a different repository); -without it, ref changes are refused for safety. - -### Typed exit codes for CI - -Both `thv skill sync` and `thv skill upgrade` use typed exit codes so CI -pipelines can distinguish outcomes: - -| Exit code | Meaning | -| --------- | ------------------------------------------------------------------------------------------------------- | -| `0` | Success | -| `1` | Command usage or setup error (standard Cobra/CLI default) | -| `2` | Check failure: `sync --check` or `upgrade --fail-on-changes` found drift; nothing was applied | -| `3` | Partial failure: some (not all) targeted skills failed during sync or upgrade | -| `4` | Policy rejection: refused non-interactively without `--yes`, or ref change without `--allow-ref-change` | - -When multiple failures apply, partial failure (`3`) takes precedence over check -failure (`2`), which takes precedence over policy rejection (`4`). - ## List and remove locally-built skill artifacts After building skills locally, you can view and manage the artifacts stored in @@ -473,8 +377,6 @@ pointing to that digest are removed. - [Manage agent skills in the ToolHive UI](../guides-ui/skills.mdx) to browse, install, and build skills without leaving the app - [`thv skill` command reference](../reference/cli/thv_skill.md) -- [`thv skill sync` command reference](../reference/cli/thv_skill_sync.md) -- [`thv skill upgrade` command reference](../reference/cli/thv_skill_upgrade.md) - [`thv serve` command reference](../reference/cli/thv_serve.md) - [Agent Skills specification](https://agentskills.io/specification) diff --git a/docs/toolhive/reference/cli/thv_skill.md b/docs/toolhive/reference/cli/thv_skill.md index 2717cddc..3a93a62f 100644 --- a/docs/toolhive/reference/cli/thv_skill.md +++ b/docs/toolhive/reference/cli/thv_skill.md @@ -38,8 +38,6 @@ The skill command provides subcommands to manage skills. * [thv skill install](thv_skill_install.md) - Install a skill * [thv skill list](thv_skill_list.md) - List installed skills * [thv skill push](thv_skill_push.md) - Push a built skill -* [thv skill sync](thv_skill_sync.md) - Restore project skills to match the lock file (experimental) * [thv skill uninstall](thv_skill_uninstall.md) - Uninstall a skill -* [thv skill upgrade](thv_skill_upgrade.md) - Upgrade project skills to newer pinned content (experimental) * [thv skill validate](thv_skill_validate.md) - Validate a skill definition diff --git a/docs/toolhive/reference/cli/thv_skill_sync.md b/docs/toolhive/reference/cli/thv_skill_sync.md deleted file mode 100644 index f7a78f99..00000000 --- a/docs/toolhive/reference/cli/thv_skill_sync.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: thv skill sync -hide_title: true -description: Reference for ToolHive CLI command `thv skill sync` -last_update: - author: autogenerated -slug: thv_skill_sync -mdx: - format: md ---- - -## thv skill sync - -Restore project skills to match the lock file (experimental) - -### Synopsis - -Restore a project's installed skills to match toolhive.lock.yaml. - -Experimental: requires TOOLHIVE_SKILLS_LOCK_ENABLED=true on the ToolHive -server while the lock file feature rolls out. - -Missing or drifted skills are reinstalled at their pinned digest. Use ---check to report drift without installing anything (suitable for CI). -Use --adopt to record lock entries for existing unmanaged installs, and ---prune to remove installs no longer present in the lock file. - -Unless --check is set, sync prompts for confirmation before installing — -skill content is a set of AI-followed instructions. Pass --yes to skip the -prompt (required in non-interactive contexts such as CI). - -``` -thv skill sync [flags] -``` - -### Options - -``` - --adopt Write lock entries for existing unmanaged project-scope installs - --check Report drift without installing, writing, or removing anything - --clients string Comma-separated target client apps (e.g. claude-code,opencode), or "all" for every available client - --format string Output format (json, text) (default "text") - -h, --help help for sync - --project-root string Project root path (default: auto-detected from the current directory) - --prune Remove installs no longer present in the lock file - --yes Skip the confirmation prompt (required when not running interactively) -``` - -### Options inherited from parent commands - -``` - --debug Enable debug mode -``` - -### SEE ALSO - -* [thv skill](thv_skill.md) - Manage skills - diff --git a/docs/toolhive/reference/cli/thv_skill_upgrade.md b/docs/toolhive/reference/cli/thv_skill_upgrade.md deleted file mode 100644 index c8ef974e..00000000 --- a/docs/toolhive/reference/cli/thv_skill_upgrade.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: thv skill upgrade -hide_title: true -description: Reference for ToolHive CLI command `thv skill upgrade` -last_update: - author: autogenerated -slug: thv_skill_upgrade -mdx: - format: md ---- - -## thv skill upgrade - -Upgrade project skills to newer pinned content (experimental) - -### Synopsis - -Re-resolve a project's lock entries and install newer content where available. - -Experimental: requires TOOLHIVE_SKILLS_LOCK_ENABLED=true on the ToolHive -server while the lock file feature rolls out. - -Skills pinned to an immutable reference (an OCI digest or a full git commit -hash) are reported not-upgradable — there is nothing newer to resolve to. -Use --preview to see what would change without persisting anything (OCI -sources are still fetched into the local artifact store to compare digests), -and --allow-ref-change to permit the resolved reference itself changing -(e.g. a registry entry repointed at a different repository). ---fail-on-changes evaluates the same plan and never installs: it is a CI -freshness gate. - -Unless --preview is set, upgrade prompts for confirmation before installing — -skill content is a set of AI-followed instructions. Pass --yes to skip the -prompt (required in non-interactive contexts such as CI). - -``` -thv skill upgrade [skill-name...] [flags] -``` - -### Options - -``` - --allow-ref-change Permit the resolved reference itself to change during upgrade - --clients string Comma-separated target client apps (e.g. claude-code,opencode), or "all" for every available client - --fail-on-changes Report what would change without installing anything; a CI freshness gate - --format string Output format (json, text) (default "text") - -h, --help help for upgrade - --preview Report what would change without persisting anything (OCI sources are still fetched to compare digests) - --project-root string Project root path (default: auto-detected from the current directory) - --yes Skip the confirmation prompt (required when not running interactively) -``` - -### Options inherited from parent commands - -``` - --debug Enable debug mode -``` - -### SEE ALSO - -* [thv skill](thv_skill.md) - Manage skills -