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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions