diff --git a/docs/toolhive/contributing.mdx b/docs/toolhive/contributing.mdx index 8c16880b..ea28c180 100644 --- a/docs/toolhive/contributing.mdx +++ b/docs/toolhive/contributing.mdx @@ -54,10 +54,9 @@ built with TypeScript and Electron, and runs on macOS, Windows, and Linux. ### ToolHive Cloud UI -The ToolHive Cloud UI is a web application for visualizing MCP servers running -in user infrastructure with easy URL copying for integration with AI agents. -Built with Next.js and TypeScript, this is an experimental project that is -actively being developed and tested. +The ToolHive Cloud UI is a web application that presents a read-only, browsable +catalog of the MCP servers in a Registry Server, with easy URL copying for +integration with AI agents. It's built with Next.js and TypeScript. **Repository**: [stacklok/toolhive-cloud-ui](https://github.com/stacklok/toolhive-cloud-ui) diff --git a/docs/toolhive/guides-cloud-ui/configuration.mdx b/docs/toolhive/guides-cloud-ui/configuration.mdx new file mode 100644 index 00000000..d78a79c9 --- /dev/null +++ b/docs/toolhive/guides-cloud-ui/configuration.mdx @@ -0,0 +1,114 @@ +--- +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. The Helm +chart does not expose these settings as individual values, so you always pass +them as container environment variables: reference a Kubernetes Secret from +`envFrom` (recommended) or list them under the chart's `env` value. + +### 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 application settings above are not first-class chart values. Pass them as +container environment variables through `envFrom` (recommended) or `env`, as +shown in [Deploy the Cloud UI](./deployment.mdx). The chart's remaining values +configure the Kubernetes Deployment and Service: + +| Value | Default | Description | +| ------------------------------------------------- | ---------------------------------------------- | --------------------------------------------------------- | +| `replicaCount` | `1` | Number of Cloud UI pods | +| `image.cloudUiImage` | Chart's release image and tag | Container image to deploy | +| `image.pullPolicy` | `IfNotPresent` | Image pull policy | +| `imagePullSecrets` | `[]` | Secrets for pulling from a private registry | +| `env` | `[]` | Inline environment variables as `name`/`value` pairs | +| `envFrom` | `[]` | Environment variables sourced from ConfigMaps or Secrets | +| `service.type` | `ClusterIP` | Service type (`ClusterIP`, `NodePort`, or `LoadBalancer`) | +| `service.port` | `80` | Service port | +| `service.targetPort` | `3000` | Container port the Service targets | +| `service.nodePort` | `null` | Node port, used only when `service.type` is `NodePort` | +| `resources` | `100m`/`128Mi` requests, `500m`/`512Mi` limits | CPU and memory requests and limits | +| `autoscaling.enabled` | `false` | Enable the Horizontal Pod Autoscaler (HPA) | +| `autoscaling.minReplicas` / `maxReplicas` | `1` / `5` | HPA replica bounds | +| `autoscaling.targetCPUUtilizationPercentage` | `80` | HPA target CPU utilization | +| `startupProbe`, `livenessProbe`, `readinessProbe` | HTTP `GET /` | Health probe configuration | +| `podSecurityContext` / `securityContext` | Non-root, UID 1001 | Pod and container security contexts | +| `serviceAccount.create` | `false` | Whether to create a ServiceAccount | +| `podAnnotations` / `podLabels` | `{}` | Extra annotations and labels on pods | +| `volumes` / `volumeMounts` | `[]` | Additional volumes and volume mounts | +| `nodeSelector` / `tolerations` / `affinity` | `{}` / `[]` / `{}` | Pod scheduling controls | + +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 or HTTPRoute template. Because it creates a +standard ClusterIP Service, you can expose the Cloud UI with an Ingress, a +Gateway API HTTPRoute, or a Service of type `LoadBalancer` or `NodePort`. See +[Step 4 of the deployment guide](./deployment.mdx#step-4-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..ffa89312 --- /dev/null +++ b/docs/toolhive/guides-cloud-ui/deployment.mdx @@ -0,0 +1,287 @@ +--- +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 deploys the ToolHive Cloud UI on a Kubernetes cluster using the Cloud +UI Helm chart, which ToolHive publishes to GitHub Container Registry (GHCR) from +the [`toolhive-cloud-ui`](https://github.com/stacklok/toolhive-cloud-ui) +repository. The Cloud UI requires both a running Registry Server and an OIDC +identity provider, so make sure you have both available before you begin. + +## 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. + +:::tip[Don't have an OIDC provider yet?] + +If you want to evaluate the Cloud UI without setting up a real identity provider +(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`). You'll set + this same public URL as `BETTER_AUTH_URL` in + [Step 2](#step-2-create-a-namespace-and-oidc-secret). +- **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: 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 3: Install the Helm chart + +Install the chart and reference the Secret you just created with `envFrom`: + +```bash title="Install the Cloud UI" +helm install cloud-ui \ + oci://ghcr.io/stacklok/toolhive-cloud-ui/toolhive-cloud-ui \ + --namespace cloud-ui \ + --set fullnameOverride=cloud-ui \ + --set envFrom[0].secretRef.name=cloud-ui-config +``` + +The `fullnameOverride=cloud-ui` flag names the Deployment and Service `cloud-ui` +so they match the commands in the rest of this guide. Without it, the chart +prefixes resources with the release name (for example, +`cloud-ui-toolhive-cloud-ui`). + +This installs the latest published chart. To pin a specific version, add +`--version `. + +Wait for the pod to become ready: + +```bash +kubectl rollout status deployment/cloud-ui -n cloud-ui --timeout=120s +``` + +:::info[What the chart deploys] + +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 4: 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 or Gateway API (recommended for shared environments) + +The chart creates a standard ClusterIP Service, so you can expose it the same +way as any other web application: with an Ingress, the Gateway API, or a +`LoadBalancer` Service. The chart does not ship an Ingress or HTTPRoute +template, so create the routing resource yourself. + +The following Ingress example uses Traefik and assumes you already have an +Ingress controller and a TLS certificate configured: + +```yaml title="cloud-ui-ingress.yaml" +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: cloud-ui + namespace: cloud-ui +spec: + ingressClassName: traefik + 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 +``` + +To expose the Cloud UI through the Gateway API instead, or for help configuring +TLS certificates, see +[Connect clients to MCP servers](../guides-k8s/connect-clients.mdx), which +covers both the Ingress and Gateway API patterns in depth. + +Make sure the host matches `BETTER_AUTH_URL` and the registered redirect URI in +your IdP. + +## Step 5: Sign in + +Open the Cloud UI in your browser. You'll land on a welcome page with a **Sign +in** button. Select it to go to your OIDC provider's sign-in page. After you +sign in successfully, the 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. + +## Uninstall the Cloud UI + +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 2](#step-2-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..11d20a6a --- /dev/null +++ b/docs/toolhive/guides-cloud-ui/index.mdx @@ -0,0 +1,32 @@ +--- +title: ToolHive Cloud UI +description: + Browse and discover 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-based catalog frontend for the Registry Server. +It gives your team a browsable interface to discover MCP servers and copy +connection URLs into their AI agents or clients, secured with your own OIDC +provider. + +## Where to start + +- **New here?** Read the [Introduction](./intro.mdx) for what the Cloud UI does, + how it's built, and how it fits with the Registry Server. +- **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-cloud-ui/intro.mdx b/docs/toolhive/guides-cloud-ui/intro.mdx new file mode 100644 index 00000000..772fa368 --- /dev/null +++ b/docs/toolhive/guides-cloud-ui/intro.mdx @@ -0,0 +1,79 @@ +--- +title: Introduction +description: + Architecture and use cases for the ToolHive Cloud UI, a read-only web catalog + backed by a Registry Server +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; +import ThemedImage from '@theme/ThemedImage'; + +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). + +::: + +:::enterprise + +Stacklok Enterprise includes an enhanced Cloud UI that builds on the open source +catalog with full management capabilities. Browse and install skills, and manage +registry sources and entries directly from the web interface. + +[Learn more about Stacklok Enterprise](../enterprise.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). + +```mermaid +flowchart LR + Browser["Browser"] --> CloudUI["Cloud UI"] + CloudUI -->|"reads catalog"| Registry["Registry Server"] + CloudUI -->|"authenticates users"| OIDC["OIDC Provider"] +``` + +## Next steps + +- [Deploy the Cloud UI](./deployment.mdx) on Kubernetes with the Helm chart, a + Registry Server, and your OIDC provider. +- [Configure the Cloud UI](./configuration.mdx) with environment variables and + OIDC settings. 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/docs/toolhive/guides-registry/publish-servers.mdx b/docs/toolhive/guides-registry/publish-servers.mdx index bdfc9062..efadb407 100644 --- a/docs/toolhive/guides-registry/publish-servers.mdx +++ b/docs/toolhive/guides-registry/publish-servers.mdx @@ -361,6 +361,8 @@ for the authorization rules. extension - [Configure authorization](./authorization.mdx) to control who can publish, read, and update entries +- [Deploy the Cloud UI](../guides-cloud-ui/index.mdx) so your team can browse + the servers you publish from a web interface ## Related information diff --git a/docs/toolhive/guides-registry/quickstart.mdx b/docs/toolhive/guides-registry/quickstart.mdx index e89736d9..bff9ab6e 100644 --- a/docs/toolhive/guides-registry/quickstart.mdx +++ b/docs/toolhive/guides-registry/quickstart.mdx @@ -390,6 +390,8 @@ deployment: chart or raw manifests - [Configure the database](./database.mdx) for production, including separate application and migration users, TLS, and persistent storage +- [Deploy the Cloud UI](../guides-cloud-ui/index.mdx) to give your team a + browsable web catalog backed by this Registry Server ## Related information diff --git a/docs/toolhive/index.mdx b/docs/toolhive/index.mdx index 4708c26e..ef4be13b 100644 --- a/docs/toolhive/index.mdx +++ b/docs/toolhive/index.mdx @@ -88,6 +88,10 @@ not just by deployment target. - The **built-in registry** is the default catalog used by the ToolHive UI and CLI to browse and install MCP servers. It is different from the Registry Server that you deploy yourself. +- [**ToolHive Cloud UI**](./guides-cloud-ui/index.mdx) is a web-based catalog + frontend for the Registry Server. It gives your team a browsable interface to + discover MCP servers and copy connection URLs, secured with your own OIDC + provider. **Choose vMCP if** you need one endpoint that aggregates multiple backend MCP servers with centralized authentication, routing, or tool optimization. @@ -164,9 +168,9 @@ It's available as part of the ToolHive Operator for Kubernetes deployments. ### Portal The ToolHive Portal is how users discover and install MCP servers. It's -available as a cross-platform desktop app (the ToolHive UI) and an experimental -[web-based frontend](https://github.com/stacklok/toolhive-cloud-ui) to the -ToolHive Registry Server. +available as a cross-platform desktop app (the ToolHive UI) and a web-based +frontend (the [Cloud UI](./guides-cloud-ui/index.mdx)) to the ToolHive Registry +Server. ### Better together @@ -245,7 +249,7 @@ effectively: **Portal:** - Cross-platform [desktop app](https://github.com/stacklok/toolhive-studio) and - browser-based [cloud UI](https://github.com/stacklok/toolhive-cloud-ui) + browser-based [Cloud UI](./guides-cloud-ui/index.mdx) - Make it easy for end users to discover and deploy MCP servers - Install MCP servers with a single click - Connect with local clients like Claude Desktop, Cursor, VS Code, and many more diff --git a/sidebars.ts b/sidebars.ts index ce98f67d..ec678d86 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -262,6 +262,22 @@ const sidebars: SidebarsConfig = { ], }, + { + type: 'category', + label: 'Cloud UI', + description: + 'How to deploy and use the ToolHive Cloud UI to browse and discover MCP servers', + link: { + type: 'doc', + id: 'toolhive/guides-cloud-ui/index', + }, + items: [ + 'toolhive/guides-cloud-ui/intro', + 'toolhive/guides-cloud-ui/deployment', + 'toolhive/guides-cloud-ui/configuration', + ], + }, + { type: 'html', value: 'Shared guides', diff --git a/static/img/toolhive/cloud-ui-dark.webp b/static/img/toolhive/cloud-ui-dark.webp new file mode 100644 index 00000000..fa9169d5 Binary files /dev/null and b/static/img/toolhive/cloud-ui-dark.webp differ diff --git a/static/img/toolhive/cloud-ui-light.webp b/static/img/toolhive/cloud-ui-light.webp new file mode 100644 index 00000000..e7c41a00 Binary files /dev/null and b/static/img/toolhive/cloud-ui-light.webp differ