Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/upstream-projects.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ projects:

- id: toolhive
repo: stacklok/toolhive
version: v0.58.0
version: v0.59.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/,
Expand Down
39 changes: 35 additions & 4 deletions docs/toolhive/guides-k8s/deploy-operator.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -306,10 +306,41 @@ resource can still point at a different Redis instance. `existingSecretKey`
defaults to `redis-password` when omitted; set it when your Secret stores the
password under a different key.

This default applies only to the simple password-authenticated Redis used for
horizontal scaling. It does not configure Sentinel, TLS, or ACL users. For those
use cases, configure session storage explicitly on each workload as described in
[Redis session storage](./redis-session-storage.mdx).
To connect to a Redis endpoint that requires TLS, enable `tls` on the default.
The operator verifies the server certificate against the system roots, or
against a CA certificate you provide in a Secret:

```yaml title="values.yaml"
operator:
defaultRedis:
addr: redis.example.com:6380
existingSecret: redis-password
existingSecretKey: password
# highlight-start
tls:
enabled: true
caCertSecretRef:
name: redis-ca
key: ca.crt
# highlight-end
```

Omit `caCertSecretRef` to verify against the system roots. `key` defaults to
`ca.crt`. TLS requires a Redis address, and the chart fails to render if you set
a CA Secret without `tls.enabled: true`. The CA Secret must exist in each
workload's namespace, not the operator namespace. If the Secret or key is
missing, affected pods stay in `ContainerCreating` with `FailedMount` events;
run `kubectl describe pod` in the workload namespace to find the missing
reference.

Workloads load the CA certificate when they start. If you rotate the certificate
in the same Secret, restart the affected workloads to pick it up. A workload
with its own `spec.sessionStorage` uses only its own settings, including TLS,
and ignores the default entirely.

The default covers a single password-authenticated Redis address, with optional
TLS. For Sentinel or ACL users, configure session storage explicitly on each
workload as described in [Redis session storage](./redis-session-storage.mdx).

:::enterprise

Expand Down
36 changes: 34 additions & 2 deletions docs/toolhive/guides-k8s/embedded-auth-server-k8s.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1028,7 +1028,9 @@ dcrConfig:
ToolHive caches the client it registers and reuses it across restarts. Each time
the proxy starts, ToolHive checks the cached client at the upstream. If the
upstream rejects it, ToolHive registers a new client and replaces the cached one
automatically.
automatically. To repeat this check while the proxy runs, set
`registrationProbeInterval` (see
[Re-check the registration while running](#re-check-the-registration-while-running)).

Choose how ToolHive runs that check with `registrationProbe` in `dcrConfig`:

Expand All @@ -1041,7 +1043,8 @@ Choose how ToolHive runs that check with `registrationProbe` in `dcrConfig`:
Use `authorizationEndpoint` for upstreams whose token endpoint answers
`invalid_grant` for any client ID, live or dropped. The probe sends no client
credentials, so it also covers `private_key_jwt` clients. The upstream sees one
abandoned authorization request each time the proxy starts.
abandoned authorization request each time the proxy starts, and on each periodic
check if you set `registrationProbeInterval`.

```yaml title="MCPExternalAuthConfig: probe the authorization endpoint"
dcrConfig:
Expand Down Expand Up @@ -1071,6 +1074,35 @@ the upstream. When the value changes, the proxy registers a new client at its
next start. Upstream refresh tokens issued to the previous client stop working,
so affected users must sign in again.

#### Re-check the registration while running

By default, a registration that the upstream drops while the proxy runs stays in
use until the proxy restarts. To detect and replace it without a restart, set
`registrationProbeInterval` in `dcrConfig` to a duration of at least `1m`. An
interval between `5m` and `15m` suits most upstreams:

```yaml title="MCPExternalAuthConfig: re-check the DCR client every 10 minutes"
dcrConfig:
discoveryUrl: 'https://mcp.example.com/.well-known/oauth-authorization-server'
# highlight-next-line
registrationProbeInterval: 10m
```

On each check, ToolHive re-reads the cached registration and checks it with the
configured `registrationProbe`. It replaces a rejected registration and
registers a new client if the cached one is missing. When the resulting client
differs from the one in use, including when another replica already replaced it,
the proxy switches to the new client without restarting.

Every replica runs its own checks. Each check sends at most one probe request to
the upstream (none when `registrationProbe` is `none`), plus a registration
request when the probe rejects the client. With the `tokenEndpoint` probe, each
check appears in the upstream's logs as a failed code redemption.

A re-registration presents the initial access token the pod read at start. If
your upstream issues single-use initial access tokens, restart the proxy to
recover from a dropped registration.

### Omit scopes on token refresh

By default, the embedded authorization server sends the configured `scopes` when
Expand Down
15 changes: 8 additions & 7 deletions docs/toolhive/guides-vmcp/embedded-auth-server-vmcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -577,13 +577,14 @@ registration endpoint bypasses discovery, so keep the authorization endpoint,
token endpoint, and scopes in the parent `oauth2Config`. With `dcrConfig`,
ToolHive obtains the client ID and secret from the DCR response.

| Field | Description |
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dcrConfig.discoveryUrl` | HTTPS URL of an RFC 8414 or OpenID Connect discovery document. |
| `dcrConfig.registrationEndpoint` | HTTPS URL of the RFC 7591 registration endpoint. |
| `dcrConfig.initialAccessTokenRef` | Optional reference to a Secret whose value ToolHive sends as a bearer token when it calls the registration endpoint. Requires `name` and `key`. |
| `dcrConfig.registrationProbe` | How ToolHive checks the cached client at start: `tokenEndpoint` (default), `authorizationEndpoint`, or `none`; see [Re-register a dropped upstream client](../guides-k8s/embedded-auth-server-k8s.mdx#re-register-a-dropped-upstream-client). |
| `dcrConfig.rotationKey` | Optional label (1-64 letters, digits, `.`, `_`, or `-`). Change it to force a fresh registration at the next start; see [Re-register a dropped upstream client](../guides-k8s/embedded-auth-server-k8s.mdx#re-register-a-dropped-upstream-client). |
| Field | Description |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dcrConfig.discoveryUrl` | HTTPS URL of an RFC 8414 or OpenID Connect discovery document. |
| `dcrConfig.registrationEndpoint` | HTTPS URL of the RFC 7591 registration endpoint. |
| `dcrConfig.initialAccessTokenRef` | Optional reference to a Secret whose value ToolHive sends as a bearer token when it calls the registration endpoint. Requires `name` and `key`. |
| `dcrConfig.registrationProbe` | How ToolHive checks the cached client: `tokenEndpoint` (default), `authorizationEndpoint`, or `none`; see [Re-register a dropped upstream client](../guides-k8s/embedded-auth-server-k8s.mdx#re-register-a-dropped-upstream-client). |
| `dcrConfig.registrationProbeInterval` | Optional duration of at least `1m`, such as `10m`. Repeats the check while vMCP runs and switches to a replacement client without a restart; see [Re-check the registration while running](../guides-k8s/embedded-auth-server-k8s.mdx#re-check-the-registration-while-running). |
| `dcrConfig.rotationKey` | Optional label (1-64 letters, digits, `.`, `_`, or `-`). Change it to force a fresh registration at the next start; see [Re-register a dropped upstream client](../guides-k8s/embedded-auth-server-k8s.mdx#re-register-a-dropped-upstream-client). |

To stop sending `scope` on refresh token requests to providers that reject it,
such as Salesforce, set `omitScopeOnRefresh: true` on the upstream's
Expand Down
6 changes: 3 additions & 3 deletions docs/toolhive/reference/cli/thv_logs.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ Use --proxy to view the logs from the ToolHive proxy process instead.

Examples:
# View logs of an MCP server
thv logs filesystem
thv logs fetch

# Follow logs in real-time
thv logs filesystem --follow
thv logs fetch --follow

# View proxy logs instead of container logs
thv logs filesystem --proxy
thv logs fetch --proxy

# Clean up old log files
thv logs prune
Expand Down
4 changes: 2 additions & 2 deletions docs/toolhive/reference/cli/thv_rm.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ Remove one or more MCP servers
Remove one or more MCP servers managed by ToolHive.
Examples:
# Remove a single MCP server
thv rm filesystem
thv rm fetch

# Remove multiple MCP servers
thv rm filesystem github slack
thv rm fetch github slack

# Remove all workloads
thv rm --all
Expand Down
4 changes: 2 additions & 2 deletions docs/toolhive/reference/cli/thv_run.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ The --network flag accepts any Docker-compatible network mode.

Examples:
# Run a server from the registry
thv run filesystem
thv run fetch

# Run a server with custom arguments and toolsets
thv run github -- --toolsets repos
Expand All @@ -97,7 +97,7 @@ Examples:
thv run npx://@modelcontextprotocol/server-everything

# Run a server in a specific group
thv run filesystem --group production
thv run fetch --group production

# Run a remote GitHub MCP server with authentication
thv run github-remote --remote-auth \
Expand Down
4 changes: 2 additions & 2 deletions docs/toolhive/reference/cli/thv_stop.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ Stop one or more MCP servers

Stop one or more running MCP servers managed by ToolHive. Examples:
# Stop a single MCP server
thv stop filesystem
thv stop fetch

# Stop multiple MCP servers
thv stop filesystem github slack
thv stop fetch github slack

# Stop all running MCP servers
thv stop --all
Expand Down
6 changes: 3 additions & 3 deletions docs/toolhive/reference/helm/operator-crds.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ Control CRD installation and preservation with these Helm values.
This reference lists values declared in the chart's default `values.yaml`.
Templates can also accept optional settings and inherited `global` values.

Chart: `toolhive-operator-crds`. Chart version: `0.58.0`. Source:
[`values.yaml`](https://github.com/stacklok/toolhive/blob/v0.58.0/deploy/charts/operator-crds/values.yaml)
at `v0.58.0`.
Chart: `toolhive-operator-crds`. Chart version: `0.59.0`. Source:
[`values.yaml`](https://github.com/stacklok/toolhive/blob/v0.59.0/deploy/charts/operator-crds/values.yaml)
at `v0.59.0`.

## Values

Expand Down
83 changes: 73 additions & 10 deletions docs/toolhive/reference/helm/operator.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ Configure the ToolHive operator with these Helm values.
This reference lists values declared in the chart's default `values.yaml`.
Templates can also accept optional settings and inherited `global` values.

Chart: `toolhive-operator`. Chart version: `0.58.0`. Source:
[`values.yaml`](https://github.com/stacklok/toolhive/blob/v0.58.0/deploy/charts/operator/values.yaml)
at `v0.58.0`.
Chart: `toolhive-operator`. Chart version: `0.59.0`. Source:
[`values.yaml`](https://github.com/stacklok/toolhive/blob/v0.59.0/deploy/charts/operator/values.yaml)
at `v0.59.0`.

## Values

Expand Down Expand Up @@ -61,14 +61,19 @@ defaultRedis:
addr: ''
existingSecret: ''
existingSecretKey: ''
tls:
caCertSecretRef:
key: ca.crt
name: ''
enabled: false
env: []
features:
experimental: false
storageVersionMigrator: true
gc:
gogc: 75
gomemlimit: 110MiB
image: ghcr.io/stacklok/toolhive/operator:v0.58.0
image: ghcr.io/stacklok/toolhive/operator:v0.59.0
imageDiscovery:
enabled: false
resources: {}
Expand Down Expand Up @@ -153,8 +158,8 @@ serviceAccount:
labels: {}
name: toolhive-operator
tolerations: []
toolhiveRunnerImage: ghcr.io/stacklok/toolhive/proxyrunner:v0.58.0
vmcpImage: ghcr.io/stacklok/toolhive/vmcp:v0.58.0
toolhiveRunnerImage: ghcr.io/stacklok/toolhive/proxyrunner:v0.59.0
vmcpImage: ghcr.io/stacklok/toolhive/vmcp:v0.59.0
volumeMounts: []
volumes: []
```
Expand Down Expand Up @@ -217,7 +222,21 @@ names. Secrets must exist in each workload's namespace.

**Type:** `object`

**Default:** `{"addr":"","existingSecret":"","existingSecretKey":""}`
<details>
<summary>Default value</summary>

```yaml
addr: ''
existingSecret: ''
existingSecretKey: ''
tls:
caCertSecretRef:
key: ca.crt
name: ''
enabled: false
```

</details>

Default Redis or Valkey session storage settings for workloads without
`spec.sessionStorage` configured.
Expand Down Expand Up @@ -251,11 +270,55 @@ namespace. Used only when a Redis address is configured.
Key containing the password in `existingSecret`. When empty, uses
`global.redis.existingSecretKey`, then `redis-password`.

### `operator.defaultRedis.tls`

**Type:** `object`

**Default:** `{"caCertSecretRef":{"key":"ca.crt","name":""},"enabled":false}`

TLS settings for the default Redis or Valkey connection. TLS is enabled only
when explicitly requested and a Redis address is configured.

### `operator.defaultRedis.tls.enabled`

**Type:** `bool`

**Default:** `false`

Verify the Redis server certificate using system roots or the optional CA
certificate below. Requires a configured Redis address.

### `operator.defaultRedis.tls.caCertSecretRef`

**Type:** `object`

**Default:** `{"key":"ca.crt","name":""}`

Optional CA certificate for verifying the Redis server. The Secret must exist in
each workload's namespace, not the operator namespace.

### `operator.defaultRedis.tls.caCertSecretRef.name`

**Type:** `string`

**Default:** `""`

Name of an existing Secret containing a PEM-encoded CA certificate. Leave empty
to use system roots.

### `operator.defaultRedis.tls.caCertSecretRef.key`

**Type:** `string`

**Default:** `"ca.crt"`

Key containing the PEM-encoded CA certificate in the Secret.

### `operator.image`

**Type:** `string`

**Default:** `"ghcr.io/stacklok/toolhive/operator:v0.58.0"`
**Default:** `"ghcr.io/stacklok/toolhive/operator:v0.59.0"`

Container image for the operator.

Expand All @@ -271,15 +334,15 @@ Image pull policy for the operator container and image-discovery containers.

**Type:** `string`

**Default:** `"ghcr.io/stacklok/toolhive/proxyrunner:v0.58.0"`
**Default:** `"ghcr.io/stacklok/toolhive/proxyrunner:v0.59.0"`

Container image for ToolHive proxy runners created by the operator.

### `operator.vmcpImage`

**Type:** `string`

**Default:** `"ghcr.io/stacklok/toolhive/vmcp:v0.58.0"`
**Default:** `"ghcr.io/stacklok/toolhive/vmcp:v0.59.0"`

Container image for Virtual MCP Server (vMCP) deployments created by the
operator.
Expand Down
Loading
Loading