diff --git a/docs/toolhive/guides-cloud-ui/configuration.mdx b/docs/toolhive/guides-cloud-ui/configuration.mdx new file mode 100644 index 00000000..78a738f4 --- /dev/null +++ b/docs/toolhive/guides-cloud-ui/configuration.mdx @@ -0,0 +1,97 @@ +--- +title: Cloud UI configuration +sidebar_label: Configuration +description: + Configure environment variables and OIDC authentication for the ToolHive Cloud + UI. +--- + +This guide covers the environment variables and OIDC settings that the ToolHive +Cloud UI reads at startup. For end-to-end deployment steps on Kubernetes, see +[Deploy the Cloud UI](./deployment.mdx). + +## Environment variables + +The Cloud UI is configured entirely through environment variables. In a +Kubernetes deployment, supply them through a Kubernetes Secret referenced from +`envFrom` (recommended) or through the chart's `env` values. + +### Required variables + +| Variable | Description | +| -------------------- | ------------------------------------------------------------------------------------------------------------- | +| `OIDC_ISSUER_URL` | Issuer URL of your OIDC provider (for example, `https://your-org.okta.com`) | +| `OIDC_CLIENT_ID` | OAuth2 client ID registered with your OIDC provider | +| `OIDC_CLIENT_SECRET` | OAuth2 client secret for the registered client | +| `BETTER_AUTH_SECRET` | Secret used to encrypt session tokens. Generate one with `openssl rand -base64 32` | +| `BETTER_AUTH_URL` | Public URL where the Cloud UI is reachable (for example, `https://cloud-ui.example.com`) | +| `API_BASE_URL` | URL of the Registry Server API (for example, `http://my-registry-api.toolhive-system.svc.cluster.local:8080`) | + +### Optional variables + +| Variable | Description | +| ----------------- | ---------------------------------------------------------------------------------------------------------------- | +| `DATABASE_URL` | PostgreSQL connection string for the auth database. When omitted, the Cloud UI uses an in-memory SQLite database | +| `TRUSTED_ORIGINS` | Comma-separated list of allowed CORS origins | + +:::warning + +The default in-memory SQLite database is not suitable for production. Sessions +are lost on pod restart and can't be shared across replicas. For multi-replica +deployments or any non-evaluation environment, set `DATABASE_URL` to point at a +managed PostgreSQL instance. + +::: + +## Configure OIDC authentication + +The Cloud UI delegates authentication to an external OIDC provider using +[Better Auth](https://www.better-auth.com/). It works with any +standards-compliant provider, including Okta, Microsoft Entra ID, Auth0, and +Keycloak. + +To configure your provider: + +1. Register a new OAuth2 / OIDC application in your identity provider. +2. Set the redirect URI to `/api/auth/callback/oidc` (for + example, `https://cloud-ui.example.com/api/auth/callback/oidc`). +3. Request the `openid`, `profile`, and `email` scopes. +4. Copy the issuer URL, client ID, and client secret into a Kubernetes Secret as + described in [Deploy the Cloud UI](./deployment.mdx). + +## Helm chart values + +The chart in +[`toolhive-cloud-ui/helm`](https://github.com/stacklok/toolhive-cloud-ui/tree/main/helm) +supports the following customizations beyond environment variables: + +- Replica count and horizontal pod autoscaling (HPA) +- Resource requests and limits +- Liveness, readiness, and startup probes +- Pod and container security contexts +- Image pull secrets for private registries +- Custom Service types (ClusterIP, NodePort) +- Additional volumes and volume mounts + +Refer to the chart's +[`values.yaml`](https://github.com/stacklok/toolhive-cloud-ui/blob/main/helm/values.yaml) +for the full set of configurable parameters and their defaults. + +:::info + +The chart does not ship an Ingress template. To expose the Cloud UI outside the +cluster, create an Ingress resource separately or use a Service of type +`NodePort` or `LoadBalancer`. See +[Step 5 of the deployment guide](./deployment.mdx#step-5-expose-the-cloud-ui) +for an Ingress example. + +::: + +## Next steps + +- [Deploy the Cloud UI](./deployment.mdx) end-to-end on Kubernetes if you + haven't already. +- [Publish servers](../guides-registry/publish-servers.mdx) to populate your + catalog with MCP server entries. +- Set up [Registry Server authentication](../guides-registry/authentication.mdx) + to control access to the catalog API the Cloud UI reads from. diff --git a/docs/toolhive/guides-cloud-ui/deployment.mdx b/docs/toolhive/guides-cloud-ui/deployment.mdx new file mode 100644 index 00000000..46028965 --- /dev/null +++ b/docs/toolhive/guides-cloud-ui/deployment.mdx @@ -0,0 +1,286 @@ +--- +title: Deploy the Cloud UI +sidebar_label: Deploy on Kubernetes +description: + Deploy the ToolHive Cloud UI on Kubernetes alongside a Registry Server, with + OIDC authentication. +--- + +This guide walks you through deploying the ToolHive Cloud UI on a Kubernetes +cluster using the Helm chart shipped in the +[`toolhive-cloud-ui`](https://github.com/stacklok/toolhive-cloud-ui) repository. +Because the Cloud UI requires both a running Registry Server and an OIDC +identity provider, it isn't a "few-minute" setup, so plan to work through this +guide end-to-end. + +## What you'll learn + +- How to install the Cloud UI Helm chart in an existing Kubernetes cluster +- How to wire the Cloud UI to a running Registry Server +- How to configure OIDC authentication using a Kubernetes Secret +- How to expose the Cloud UI for browser access + +## Prerequisites + +Before starting, make sure you have: + +- A running Kubernetes cluster (v1.24+). The + [Registry Server quickstart](../guides-registry/quickstart.mdx) walks through + a local kind cluster you can reuse. +- A **Registry Server** reachable from the cluster. If you don't have one yet, + complete the [Registry Server quickstart](../guides-registry/quickstart.mdx) + first. Take note of the in-cluster Service name and port (the quickstart + exposes `my-registry-api:8080` in the `toolhive-system` namespace). +- An **OIDC application** registered with your identity provider (Okta, + Microsoft Entra ID, Auth0, Keycloak, or any standards-compliant provider). + You'll need the issuer URL, client ID, and client secret. +- [`kubectl`](https://kubernetes.io/docs/tasks/tools/) and + [Helm](https://helm.sh/docs/intro/install/) v3.10+ installed locally. +- [Git](https://git-scm.com/downloads) to clone the chart repository. + +:::tip[Don't have an OIDC provider yet?] + +If you want to evaluate the Cloud UI without setting up a real IdP, the +`toolhive-cloud-ui` repository includes a mock OIDC provider for local +development. See the +[repository README](https://github.com/stacklok/toolhive-cloud-ui#development-modes) +for details. Use the Kubernetes path below for any environment beyond local +evaluation. + +::: + +## Step 1: Register the OIDC application + +In your identity provider, create a new OAuth2 / OIDC application with the +following settings: + +- **Application type**: Web application +- **Redirect URI**: `/api/auth/callback/oidc`, where + `` is the public URL where you plan to expose the Cloud UI (for + example, `https://cloud-ui.example.com/api/auth/callback/oidc`). +- **Scopes**: `openid`, `profile`, `email` + +Copy the **issuer URL**, **client ID**, and **client secret** that your provider +returns. You'll reference them in the next step. + +## Step 2: Clone the chart repository + +The Helm chart lives inside the `toolhive-cloud-ui` repository under `helm/`. +Clone it to your workstation: + +```bash +git clone https://github.com/stacklok/toolhive-cloud-ui.git +cd toolhive-cloud-ui +``` + +## Step 3: Create a namespace and OIDC Secret + +Create a namespace for the Cloud UI and a Kubernetes Secret that holds the +sensitive configuration. Storing credentials in a Secret keeps them out of your +Helm values file and chart history. + +```bash +kubectl create namespace cloud-ui +``` + +```bash +kubectl create secret generic cloud-ui-config \ + -n cloud-ui \ + --from-literal=OIDC_ISSUER_URL=https://your-org.okta.com \ + --from-literal=OIDC_CLIENT_ID= \ + --from-literal=OIDC_CLIENT_SECRET= \ + --from-literal=BETTER_AUTH_SECRET=$(openssl rand -base64 32) \ + --from-literal=BETTER_AUTH_URL=https://cloud-ui.example.com \ + --from-literal=API_BASE_URL=http://my-registry-api.toolhive-system.svc.cluster.local:8080 +``` + +Replace the placeholder values: + +- `OIDC_ISSUER_URL`, `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET`: values from + [Step 1](#step-1-register-the-oidc-application). +- `BETTER_AUTH_URL`: the public URL where users will reach the Cloud UI. +- `API_BASE_URL`: the in-cluster URL of the Registry Server Service. If you + followed the [Registry Server quickstart](../guides-registry/quickstart.mdx), + it's `http://my-registry-api.toolhive-system.svc.cluster.local:8080`. + +See [Configuration](./configuration.mdx) for the full list of supported +environment variables. + +## Step 4: Install the Helm chart + +Install the chart from the cloned repository and reference the Secret you just +created with `envFrom`: + +```bash title="Install the Cloud UI" +helm install cloud-ui ./helm \ + --namespace cloud-ui \ + --set envFrom[0].secretRef.name=cloud-ui-config +``` + +Wait for the pod to become ready: + +```bash +kubectl rollout status deployment/cloud-ui -n cloud-ui --timeout=120s +``` + +:::info[What's happening?] + +The chart deploys the Cloud UI as a single-replica Deployment with a ClusterIP +Service on port 80 that targets the container on port 3000. The container reads +all OIDC and Registry Server settings from the Secret you mounted with +`envFrom`. Check `helm/values.yaml` in the repository for the full set of +configurable parameters (replicas, resources, probes, HPA, security context). + +::: + +## Step 5: Expose the Cloud UI + +The chart creates a ClusterIP Service by default. To make the Cloud UI reachable +from a browser, choose one of the following options. + +### Option A: Port-forward (testing only) + +For testing, forward the Service port to your local machine: + +```bash +kubectl port-forward svc/cloud-ui 3000:80 -n cloud-ui +``` + +Open `http://localhost:3000` in your browser. For this to work end-to-end, set +`BETTER_AUTH_URL=http://localhost:3000` and register the matching redirect URI +(`http://localhost:3000/api/auth/callback/oidc`) in your OIDC application. + +### Option B: Ingress (recommended for shared environments) + +For shared or production deployments, expose the Cloud UI through an Ingress +controller. The chart does not ship an Ingress template, so create one yourself. +The example below assumes you have an Ingress controller (such as NGINX) and a +TLS certificate already configured: + +```yaml title="cloud-ui-ingress.yaml" +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: cloud-ui + namespace: cloud-ui +spec: + ingressClassName: nginx + tls: + - hosts: + - cloud-ui.example.com + secretName: cloud-ui-tls + rules: + - host: cloud-ui.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: cloud-ui + port: + number: 80 +``` + +Apply the manifest: + +```bash +kubectl apply -f cloud-ui-ingress.yaml +``` + +Make sure the host matches `BETTER_AUTH_URL` and the registered redirect URI in +your IdP. + +## Step 6: Sign in + +Open the Cloud UI in your browser. You should be redirected to your OIDC +provider's sign-in page. After signing in successfully, your provider redirects +you back to the Cloud UI's `/catalog` page where you can: + +- Browse MCP servers registered in your Registry Server +- View server details and connection information +- Copy server URLs into your AI agents or MCP clients + +If sign-in fails, see the [Troubleshooting](#troubleshooting) section below. + +## Clean up + +To remove the Cloud UI deployment: + +```bash +helm uninstall cloud-ui -n cloud-ui +kubectl delete namespace cloud-ui +``` + +This leaves the Registry Server and your IdP application untouched. + +## Next steps + +- [Cloud UI configuration](./configuration.mdx) covers every supported + environment variable, including optional persistence with PostgreSQL and CORS + origins. +- [Publish servers](../guides-registry/publish-servers.mdx) to populate the + catalog that the Cloud UI displays. +- [Set up Registry Server authentication](../guides-registry/authentication.mdx) + to protect the catalog API the Cloud UI reads from. + +## Related information + +- [Registry Server quickstart](../guides-registry/quickstart.mdx) - deploy the + backend the Cloud UI depends on +- [Deploy the Registry Server](../guides-registry/deployment.mdx) - production + deployment patterns for the Registry Server + +## Troubleshooting + +
+Sign-in redirects to the IdP but never returns to the Cloud UI + +The most common cause is a mismatch between the redirect URI registered in your +IdP and the value the Cloud UI sends. Confirm that: + +- `BETTER_AUTH_URL` in the Secret matches the public URL the browser uses to + reach the Cloud UI (scheme, host, and port). +- The redirect URI registered in your IdP is exactly + `/api/auth/callback/oidc`. + +Restart the pod after changing the Secret so the new values take effect: + +```bash +kubectl rollout restart deployment/cloud-ui -n cloud-ui +``` + +
+ +
+Catalog page shows no MCP servers + +The Cloud UI talks to the Registry Server through `API_BASE_URL`. If the catalog +is empty: + +1. Confirm the Registry Server is reachable from inside the cluster: + + ```bash + kubectl run curl --rm -it --image=curlimages/curl --restart=Never -- \ + curl -s http://my-registry-api.toolhive-system.svc.cluster.local:8080/registry/default/v0.1/servers + ``` + +2. Confirm the registry has at least one server published. See + [Publish servers](../guides-registry/publish-servers.mdx). + +
+ +
+Pod fails to start with missing environment variable errors + +The Cloud UI requires all six environment variables listed in +[Step 3](#step-3-create-a-namespace-and-oidc-secret). Confirm the Secret +contains every key: + +```bash +kubectl describe secret cloud-ui-config -n cloud-ui +``` + +Recreate the Secret with the missing keys, then restart the deployment. + +
diff --git a/docs/toolhive/guides-cloud-ui/index.mdx b/docs/toolhive/guides-cloud-ui/index.mdx new file mode 100644 index 00000000..fef6cb42 --- /dev/null +++ b/docs/toolhive/guides-cloud-ui/index.mdx @@ -0,0 +1,72 @@ +--- +title: ToolHive Cloud UI +description: + Browse and manage MCP servers from a web-based catalog backed by the Registry + Server +--- + +import DocCardList from '@theme/DocCardList'; + +## Introduction + +The ToolHive Cloud UI is a web application that gives your team a shared catalog +of MCP servers. It connects to a [Registry Server](../guides-registry/index.mdx) +and displays every registered server in a browsable interface, so team members +can discover available servers and copy connection URLs into their AI agents or +clients. + +Use the Cloud UI when you want to: + +- Give your team a single place to discover MCP servers without using the CLI or + desktop app. +- Provide a self-service catalog where users copy server URLs directly into + their AI workflows. +- Layer authentication on top of the catalog with your existing identity + provider (IdP). + +:::note + +The Cloud UI is a **read-oriented catalog** that works alongside the Registry +Server. It does not start or stop MCP servers. To manage server lifecycles, use +the [ToolHive CLI](../guides-cli/index.mdx), +[ToolHive UI](../guides-ui/index.mdx), or +[Kubernetes Operator](../guides-k8s/index.mdx). + +::: + +## Architecture overview + +The Cloud UI is a Next.js application with two main dependencies: + +- **Registry Server** - provides the MCP server catalog through the + [MCP Registry API](../reference/registry-api.mdx). The Cloud UI reads server + entries from this API. +- **OIDC provider** - handles user authentication. The Cloud UI uses + [Better Auth](https://www.better-auth.com/) with any standards-compliant OIDC + provider (Okta, Microsoft Entra ID, Auth0, and others). + +```text ++-----------+ +----------+ +-----------------+ +| Browser | ----> | Cloud UI | ----> | Registry Server | ++-----------+ +----------+ +-----------------+ + | + v + +---------------+ + | OIDC Provider | + +---------------+ +``` + +## Where to start + +- **Setting up the backend first?** The Cloud UI requires a running Registry + Server. Start with the + [Registry Server quickstart](../guides-registry/quickstart.mdx) to get one + running on Kubernetes. +- **Ready to deploy?** Follow [Deploy the Cloud UI](./deployment.mdx) to install + the Helm chart and wire it up to a Registry Server and your OIDC provider. +- **Configuring a deployment?** See [Configuration](./configuration.mdx) for the + full list of environment variables and OIDC settings. + +## Contents + + diff --git a/docs/toolhive/guides-registry/index.mdx b/docs/toolhive/guides-registry/index.mdx index 3209da8d..ef21ff2c 100644 --- a/docs/toolhive/guides-registry/index.mdx +++ b/docs/toolhive/guides-registry/index.mdx @@ -31,6 +31,14 @@ If you want to host and operate your own catalog, use the Registry Server. If you only need to browse the default ToolHive catalog from the UI or CLI, you do not need to deploy it. +:::tip + +Want a web-based interface for your Registry Server catalog? The +[Cloud UI](../guides-cloud-ui/index.mdx) connects to the Registry Server and +gives your team a browsable catalog with OIDC-based authentication. + +::: + ## Where to start - **New to the Registry Server?** Follow the diff --git a/sidebars.ts b/sidebars.ts index bd77117e..b68a2cdf 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -261,6 +261,21 @@ const sidebars: SidebarsConfig = { ], }, + { + type: 'category', + label: 'Cloud UI', + description: + 'How to deploy and use the ToolHive Cloud UI to browse and manage MCP servers', + link: { + type: 'doc', + id: 'toolhive/guides-cloud-ui/index', + }, + items: [ + 'toolhive/guides-cloud-ui/deployment', + 'toolhive/guides-cloud-ui/configuration', + ], + }, + { type: 'html', value: 'Shared guides',