Skip to content
Open
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
15 changes: 9 additions & 6 deletions docs/toolhive/guides-registry/audit-logging.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,12 @@ kubectl logs -n <NAMESPACE> deployment/toolhive-registry-api \

## Next steps

- [Configure authentication](./authentication.mdx) to ensure caller identity
appears in `subjects`
- [Configure authorization](./authorization.mdx) to control which roles can
perform which operations
- [Configure telemetry](./telemetry-metrics.mdx) for distributed tracing and
metrics alongside audit logs
- [Configure telemetry](./telemetry-metrics.mdx) for metrics and distributed
tracing alongside audit logs

## Related information

- [Authentication](./authentication.mdx) - audit `subjects` come from the
authenticated caller identity
- [Authorization](./authorization.mdx) - controls which roles can perform the
operations you audit
14 changes: 5 additions & 9 deletions docs/toolhive/guides-registry/authentication.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
---
title: Authentication configuration
description:
How to configure authentication for the ToolHive Registry Server with
anonymous and OAuth modes
Configure anonymous or OAuth authentication for the ToolHive Registry Server
---

The Registry server provides secure-by-default authentication, defaulting to
The Registry Server provides secure-by-default authentication, defaulting to
OAuth mode to protect your registry. You can configure authentication to fit
different deployment scenarios, from development environments to production
deployments with enterprise identity providers.
Expand Down Expand Up @@ -134,9 +133,9 @@ introspection if needed.

## Kubernetes authentication

For Kubernetes deployments, you can configure OAuth to validate service account
tokens. This provides automatic, zero-config authentication for workloads
running in the cluster.
For Kubernetes deployments, you can configure OAuth to validate projected
service account tokens. This lets workloads use their Kubernetes identities
instead of separate application credentials.

### Kubernetes provider configuration

Expand Down Expand Up @@ -520,9 +519,6 @@ providers:

- [Configure authorization](./authorization.mdx) to set up role-based access
control and claims-based scoping
- [Set up the database](./database.mdx) for production storage and migrations
- [Configure telemetry](./telemetry-metrics.mdx) for distributed tracing and
metrics collection

## Troubleshooting

Expand Down
77 changes: 44 additions & 33 deletions docs/toolhive/guides-registry/authorization.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,13 @@ description:
Registry Server
---

The Registry server provides a claims-based authorization model that controls
The Registry Server provides a claims-based authorization model that controls
who can manage sources, registries, and entries. Authorization builds on top of
[authentication](./authentication.mdx). You need OAuth authentication enabled
before configuring authorization.

## How authorization works

When a client accesses registry data, the server checks three layers in order:

1. **Registry claims** (access gate): can the caller access this registry at
all? If the registry has claims and the caller's JWT doesn't satisfy them,
the server returns `403 Forbidden` before any data is returned.
2. **Entry claims** (visibility filter): which entries can the caller see? Each
entry can carry claims inherited from its source (for synced sources) or set
explicitly (via publish payload or Kubernetes annotation). Only entries whose
claims the caller's JWT satisfies are included in the response.
3. **Role checks** (admin operations): can the caller perform this write
operation? Publishing, deleting, and managing sources/registries require
specific [roles](#configure-roles).

When a caller makes an API request, the server:

1. Extracts the caller's claims from their JWT token
Expand All @@ -44,6 +31,20 @@ flowchart LR
ClaimCheck -->|No| Deny403
```

### Claim scopes

Claims attach to three kinds of resource. Each scope controls a different part
of the request:

| Scope | What its claims govern |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Registry claims** | Access to the registry's consumer API. A caller whose JWT doesn't satisfy them gets `403` on the whole `/registry/{name}` surface. |
| **Entry claims** | Per-entry visibility within a registry the caller can already reach. A consumer sees an entry only if their JWT satisfies both the registry's claims and the entry's claims. |
| **Source claims** | Admin visibility of the source, linking the source into a registry, and publishing into a managed source. Source claims never filter entries at read time. |

See [Source claims](#source-claims) for how each source type assigns claims to
its entries.

## Configure roles

Define roles in the `auth.authz.roles` section of your configuration file. Each
Expand Down Expand Up @@ -131,11 +132,23 @@ For synced sources (Git, API, File), claims on a source are **inherited by all
entries** during sync. Every MCP server or skill ingested from that source
carries the source's claims.

For Kubernetes and managed sources, source claims control who can manage the
source via the admin API but are **not** inherited by entries. Kubernetes
entries get claims from the
For Kubernetes and managed sources, source claims are **not** inherited by
entries. Kubernetes entries get claims from the
[`authz-claims` annotation](./configuration.mdx#per-entry-claims-via-annotation)
on each CRD. Managed source entries get claims from the publish request payload.
on each CRD, and managed source entries get claims from the publish request
payload.

A managed source's own claims decide who can publish into it. To publish, a
caller needs the `manageEntries` role, and their JWT must satisfy the source's
existing claims using the [visibility rule](#claim-matching-rules). A managed
source with no claims can only be published to by a super-admin.

This check controls publishing, not entry visibility. Give the source a claim
that matches everyone who should be able to publish there, such as
`org: "acme"`. Each published entry's own claims control who can read it.

Source claims also decide who can see and manage the source through the admin
API, and whether the source can be added to a registry.

```yaml title="config-source-claims.yaml"
sources:
Expand Down Expand Up @@ -204,10 +217,10 @@ that differ only in how they handle array-valued claims. Every check does an AND
across keys (the caller must satisfy every key present on the resource), and
both rules default-deny on unlabeled resources.

| Rule | Within-array test | Used for |
| -------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Visibility** | OR - the caller must share **any one** array value | Reads and access gates: list and get on sources, registries, and entries; the registry access gate on `/registry/{name}`; delete on sources, registries, and entry versions. |
| **Subset** | AND - the caller must hold **every** array value | Writes: create or update a source or registry; publish an entry; update the claims on a published entry. Applied to the **incoming** claims in the request, not to the resource's existing tags. |
| Rule | Within-array test | Used for |
| -------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Visibility** | OR - the caller must share **any one** array value | Reads and access gates: list and get on sources, registries, and entries; the registry access gate on `/registry/{name}`; publishing into a managed source; delete on sources, registries, and entry versions. |
| **Subset** | AND - the caller must hold **every** array value | Writes: create or update a source or registry; set incoming entry claims during publish; update the claims on a published entry. Applied to the **incoming** claims in the request, not to the resource's existing tags. |

For scalar (string) claims the two rules behave identically. The difference only
shows up on array values.
Expand Down Expand Up @@ -280,8 +293,9 @@ on the next sync.

## Claims on published entries

When you publish an MCP server version or skill to a managed source, you can
attach claims to the entry. The server enforces three rules:
Before publishing, your JWT must satisfy the managed source's existing claims.
See [Source claims](#source-claims). The server then enforces three rules on the
entry's claims:

1. **Claims are required when authentication is enabled.** Publishing without
claims, or with an empty `claims` object, against an authenticated endpoint
Expand Down Expand Up @@ -535,8 +549,9 @@ With this configuration:
- **Data team members** (JWT with `org: "acme"`, `team: "data"`) can access the
`data` registry and see entries from `data-tools` and `shared`.
- **Writers** in the `acme` org (JWT with `org: "acme"`, `role: "writer"`) can
publish to the `shared` managed source. The `org: "acme"` claim on the source
is what makes it reachable to non-super-admin callers under default-deny.
publish to the `shared` managed source because their JWT satisfies the
source's `org: "acme"` claim. Publishing checks that source claim, so without
it only super-admins could publish to the source (default-deny).
- **Admins** (JWT with `org: "acme"`, `role: "admin"`) can manage sources and
registries within the `acme` org.
- **Super-admins** (JWT with `role: "super-admin"`) can access and manage
Expand All @@ -551,14 +566,10 @@ that team's registry surfaces the entry. See

## Next steps

- [Configure authentication](./authentication.mdx) to set up OAuth providers
- [Configure audit logging](./audit-logging.mdx) to track who does what in the
registry
- [Configure sources and registries](./configuration.mdx) to set up your data
sources
- [Manage skills](./skills.mdx) to publish and discover reusable skills
- [Configure audit logging](./audit-logging.mdx) to record who performs which
operations

## Related information

- [Registry server introduction](./intro.mdx) - architecture and features
- [Registry Server introduction](./intro.mdx) - architecture and features
overview
19 changes: 9 additions & 10 deletions docs/toolhive/guides-registry/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -358,10 +358,11 @@ exists in the database.
- `GET /registry/{registryName}/v0.1/...` - List and retrieve servers and skills
- [Skills management](./skills.mdx) via the extensions API

When authentication is enabled, publish requests must include a `claims` object.
See
[Claims on published entries](./authorization.mdx#claims-on-published-entries)
for the full rules.
When authentication is enabled, the caller needs the `manageEntries` role, and
publish requests must include a `claims` object whose values are backed by a JWT
that satisfies the managed source's claims. See
[Claim scopes](./authorization.mdx#claim-scopes) for how source and entry claims
apply during publishing.

See [Publish MCP servers](./publish-servers.mdx) for request examples covering
publish, delete, and claims updates, or the
Expand Down Expand Up @@ -496,7 +497,7 @@ that follows the MCP specification. Each tool definition can include:
- `outputSchema`: JSON Schema describing the tool's output format
- `annotations`: Additional metadata about the tool

The Registry server validates JSON syntax only. Schema validation is performed
The Registry Server validates JSON syntax only. Schema validation is performed
by the operator during resource reconciliation. If the annotation contains
invalid JSON, a warning is logged and the tool definitions are omitted from the
registry, but the server is still registered normally.
Expand All @@ -521,7 +522,7 @@ URL within the publisher-provided metadata:
The registry URL from the `registry-url` annotation becomes a key in the JSON
structure.

This feature requires the Registry server to be granted access to those
This feature requires the Registry Server to be granted access to those
resources via a Service Account. See the
[deployment section](./deploy-manual.mdx#workload-discovery) for details.

Expand Down Expand Up @@ -708,7 +709,5 @@ precedence order.
- [Publish MCP servers](./publish-servers.mdx) to a Git, file, or managed source
- [Configure authentication](./authentication.mdx) to secure access to your
registry
- [Set up authorization](./authorization.mdx) to control access with roles and
claims
- [Set up the database](./database.mdx) for production storage
- [Configure audit logging](./audit-logging.mdx) to track API operations
- [Configure authorization](./authorization.mdx) to control access with roles
and claims
18 changes: 10 additions & 8 deletions docs/toolhive/guides-registry/database.mdx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
---
title: Database configuration
description:
How to configure PostgreSQL database storage and migrations for the ToolHive
Registry server
Configure PostgreSQL storage, connection pooling, and migrations for the
ToolHive Registry Server
---

The Registry server requires a PostgreSQL database for storing registry state
and metadata. This enables persistence across restarts and provides a foundation
for advanced features.
The Registry Server stores registry state and metadata in a PostgreSQL database,
which persists data across restarts. The [deployment guides](./deployment.mdx)
include the minimal connection settings needed to get a server running; this
page covers the production decisions layered on top: separate migration and
application users, TLS, connection pooling, automatic migrations, and dynamic
credential mechanisms.

## Supported versions

Expand Down Expand Up @@ -322,9 +325,8 @@ database:

## Next steps

- [Configure telemetry](./telemetry-metrics.mdx) for distributed tracing and
metrics collection
- [Deploy the server](./deployment.mdx) to your Kubernetes environment
- [Configure sources and registries](./configuration.mdx) to define and evolve
your catalog

## Troubleshooting

Expand Down
4 changes: 2 additions & 2 deletions docs/toolhive/guides-registry/deploy-helm.mdx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
title: Deploy with Helm
description:
How to deploy the ToolHive Registry Server in Kubernetes using the official
Helm chart
Deploy the ToolHive Registry Server in Kubernetes using the official Helm
chart
---

:::info
Expand Down
32 changes: 23 additions & 9 deletions docs/toolhive/guides-registry/deploy-manual.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,22 @@ For alternative deployment approaches, see
Below is an example Kubernetes Deployment configuring the ToolHive Registry
Server to expose a single static registry based on a Git repository.

This example assumes that a PostgreSQL 14 or later database is available at
`db.example.com` and the necessary users for migration and application execution
are configured and able to connect to a `registry` database. It also assumes
that you have a keycloak instance configured to act as identity provider.
## Prerequisites

- A Kubernetes cluster (current and two previous minor versions are supported)
- Permissions to create resources in the cluster
- [`kubectl`](https://kubernetes.io/docs/tasks/tools/) configured to communicate
with your cluster
- PostgreSQL 14 or later
- An OIDC identity provider (this example uses Keycloak)

## Example deployment

All resources are created in the `toolhive-system` namespace. This namespace
must exist before applying the deployment.
This example assumes that the PostgreSQL database is available at
`db.example.com` and the necessary users for migration and application execution
are configured and able to connect to a `registry` database. All resources are
created in the `toolhive-system` namespace, which must exist before applying the
deployment.

For further details about user grants read the
[Migration user privileges](./database.mdx#migration-user-privileges) and
Expand Down Expand Up @@ -182,7 +191,7 @@ of workloads. The types being watched are
[`MCPRemoteProxy`](../guides-k8s/remote-mcp-proxy.mdx), and
[`VirtualMCPServer`](../guides-vmcp/configuration.mdx).

By default, the Registry server discovers resources in all namespaces
By default, the Registry Server discovers resources in all namespaces
(cluster-wide). You can restrict discovery to specific namespaces by setting the
`THV_REGISTRY_WATCH_NAMESPACE` environment variable to a comma-separated list of
namespace names in your deployment:
Expand Down Expand Up @@ -392,6 +401,11 @@ re-apply it before or alongside the Deployment change. See
sources and sync policies
- [Set up authentication](./authentication.mdx) to secure access to your
registry
- [Set up authorization](./authorization.mdx) to control access with roles and
claims
- [Configure telemetry](./telemetry-metrics.mdx) to monitor your deployment

## Related information

- [Database configuration](./database.mdx) for the pgpass format and user
privileges
- [Quickstart: Registry Server](./quickstart.mdx) for a hands-on walkthrough of
a minimal local deployment
Loading