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/, diff --git a/docs/toolhive/concepts/cedar-policies.mdx b/docs/toolhive/concepts/cedar-policies.mdx index a132b9f7..cdfe25cb 100644 --- a/docs/toolhive/concepts/cedar-policies.mdx +++ b/docs/toolhive/concepts/cedar-policies.mdx @@ -125,6 +125,12 @@ 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 (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. ## Writing effective policies diff --git a/docs/toolhive/concepts/embedded-auth-server.mdx b/docs/toolhive/concepts/embedded-auth-server.mdx index d02edbc9..0a0e9970 100644 --- a/docs/toolhive/concepts/embedded-auth-server.mdx +++ b/docs/toolhive/concepts/embedded-auth-server.mdx @@ -126,6 +126,63 @@ 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 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 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..f662d0f2 100644 --- a/docs/toolhive/concepts/mcp-primer.mdx +++ b/docs/toolhive/concepts/mcp-primer.mdx @@ -160,10 +160,11 @@ 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 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/guides-cli/build-containers.mdx b/docs/toolhive/guides-cli/build-containers.mdx index 47896f98..c631eb3b 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. + +:::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 +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-k8s/deploy-operator.mdx b/docs/toolhive/guides-k8s/deploy-operator.mdx index 7e298b7d..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 @@ -436,6 +461,43 @@ 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. + ## 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..51c9e9bb 100644 --- a/docs/toolhive/guides-k8s/rate-limiting.mdx +++ b/docs/toolhive/guides-k8s/rate-limiting.mdx @@ -51,8 +51,12 @@ 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 + +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. diff --git a/docs/toolhive/reference/authz-policy-reference.mdx b/docs/toolhive/reference/authz-policy-reference.mdx index d55a780d..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 @@ -121,6 +125,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 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/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"