Skip to content

Enterprise UI does not consume directives from /enterprise/api/v1beta/config #2240

@reyortiz3

Description

@reyortiz3

Summary

The Enterprise Studio Desktop app polls GET /enterprise/api/v1beta/config (provided by the enterprise overlay of thv serve) and extracts only state, warning, and policy from the response — ignoring the individual policy directives in the payload (playground, non_registry_servers, registry, telemetry, …).

As a result, when an administrator pushes a directive like playground: { value: false, enforcement: enforced } via the enterprise config server, the directive is signed into envelopes, propagated correctly to the Desktop's thv serve subprocess, and visible in the API response — but the Desktop UI takes no action. The Playground tab remains visible.

The permission keys, the gate, and the React data flow are all wired — only the mapping from directive value to permission state is missing.

Repro

  1. Deploy an enterprise-manager / config-server with a playground directive:
    enterprise-manager:
      enterpriseConfig:
        playground:
          value: false
          enforcement: "enforced"
  2. Sign in to ToolHive Studio Enterprise; let it fetch a fresh envelope.
  3. Inspect the live API response:
    DESKTOP_PORT=$(ps -ef | grep -v grep | grep "ToolHiveStudioEnterprise.*thv serve" | head -1 \
      | grep -oE -- "--port=[0-9]+" | grep -oE "[0-9]+")
    curl -s http://127.0.0.1:$DESKTOP_PORT/enterprise/api/v1beta/config | jq
    Output (truncated):
    {
      "playground": { "value": false, "enforcement": "enforced" },
      "state": "online"
    }
  4. Observe the Desktop UI — Playground tab still visible in the left navigation.

Expected

When playground.value === false is present in the envelope, the Desktop should hide the Playground tab. Same for any other directive whose semantics map to a UI permission.

Where the gap is (from a decompile of the bundled app)

The permission keys are defined and consumed correctly:

xB = {
  AUTO_UPDATE:           "auto-update",
  CUSTOM_MCP_SERVERS:    "non_registry_servers",
  HELP_MENU:             "help-menu",
  PLAYGROUND_MENU:       "playground-menu",
  SETTINGS_REGISTRY_TAB: "settings-registry-tab",
};

// Used to gate the Playground tab:
t(xB.PLAYGROUND_MENU) && <PlaygroundMenuItem />

// canShow returns true by default if the key is missing:
function canShow(key) { return permissions[key] ?? true; }

But the React Query loader that polls the enterprise config only extracts state/warning/policy — it discards every directive:

function FH() {
  let { data: e } = useQuery({
    queryKey: ["enterprise", "config"],
    queryFn: async () => { let {data} = await NH(); return data ?? null; },
    refetchOnWindowFocus: true,
    refetchInterval: ...,
  });
  return { state: e?.state, warning: e?.warning, policy: e?.policy };
  // ← directives like e?.playground are not extracted, never reach the permissions context
}

Suggested fix

Extend the loader to translate directives into the permissions shape:

return {
  state:   e?.state,
  warning: e?.warning,
  policy:  e?.policy,
  permissions: {
    "playground-menu":     e?.playground?.value !== false,
    "non_registry_servers": e?.non_registry_servers?.value !== false,
    // … any other directive → permission mappings
  },
};

…and feed the permissions field into the existing wB context that backs canShow. The rest of the UI is already wired.

Impact

  • Enterprise administrators pushing UI-restriction directives (e.g. hide Playground for dev teams that should only run pre-approved MCP servers) see no behavior change in the Desktop, despite the directive being correctly signed, transported, and stored. The admin assumes the policy is broken.
  • Similar bug for non_registry_servers: thv serve enforces it at the API level (refuses to start non-registry servers), but the UI doesn't proactively hide the "add custom server" affordance — users hit the error only after attempting, and there's no admin-message banner.
  • Related (separate issue): when the config server enters offline_grace_period / offline_degraded, the Desktop DOES show a banner (good!) — but it does not display the degraded_mode.message value the admin configured in values.yaml. Worth folding in.

Versions tested: ToolHive Studio Enterprise 0.1.30 (built e8abecc).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions