Skip to content

[Chore] Remove MCP Optimizer from the UI #2087

@samuv

Description

@samuv

Goal

Remove the MCP Optimizer feature from the ToolHive Studio UI and ensure that users upgrading from a version where the optimizer was enabled are migrated cleanly on startup, so they don't end up with an orphaned __mcp-optimizer__ group, a dangling meta-mcp workload, or clients registered to a group that no longer has a UI surface.

This follows #1910, which shipped the deprecation banner and prepared users for the sunset.

Why

The MCP Optimizer was an experimental feature that has been deprecated. Keeping the code, routes, hooks, and UI branches around adds maintenance cost, complicates the MCP servers / groups / clients flows with optimizer-specific branches, and leaves users who had previously enabled it in an inconsistent state after upgrade.

Scope

Remove from the product

  • Route + UI surface: /mcp-optimizer, the sunset banner (McpOptimizerSunsetBanner), the entire features/meta-mcp module (group selector, loading dialog, optimizer warnings, and backing hooks).
  • All optimizer-specific branches in the MCP servers sidebar, group actions, network isolation tab, local-mcp form, clients button, and the registry / run-custom / run-remote / update / restart / stop / delete orchestration.
  • Supporting hooks: use-create-optimizer-group, use-optimize-group-name, use-is-optimized-group-name, use-mcp-optimizer-banner-visible, use-notification-optimizer, and their tests.
  • Config: drop the toolhive-mcp-optimizer image from renovate.json, drop MCP_OPTIMIZER_SUNSET_BLOG_URL from common/app-info.ts, trim constants.ts down to the identifiers still needed by the cleanup migration.

Keep for one release

  • META_OPTIMIZER remains in the feature-flag registry but set to isDisabled: true. It never shows up in experimental settings and always returns false, but the key is preserved so the cleanup path can observe prior state. To be removed entirely in the next release.
  • MCP_OPTIMIZER_GROUP_NAME / META_MCP_SERVER_NAME constants stay in constants.ts because the cleanup hook depends on them. They can be inlined or deleted once the META_OPTIMIZER flag is removed.

Startup migration

  • A new useMcpOptimizerStartupCleanup hook runs at most once per session from RootComponent. It awaits electronAPI.isToolhiveRunning() (polling up to 60s) before marking itself as run, then invokes cleanupMetaOptimizer().
  • useCleanupMetaOptimizer is rewritten so the cleanup is self-contained and callable from outside a component. It fetches groups and the toolhive-mcp-optimizer workload at call-time via queryClient.fetchQuery, then:
    1. If the meta-mcp workload has ALLOWED_GROUPS pointing at a user group that still exists, re-registers the optimizer-group clients to that target group.
    2. Deletes the __mcp-optimizer__ group with ?with-workloads=true, taking the meta-mcp workload with it.
  • Cleanup is a no-op when the optimizer group doesn't exist, so users who never enabled the feature pay nothing at startup.

The cleanup path is intentionally the same teardown that used to run when the user flipped the experimental toggle off — nothing new is introduced, only relocated so it now fires automatically on first launch post-upgrade.

Acceptance criteria

  • /mcp-optimizer route, the sunset banner, and all optimizer-related UI affordances are gone.
  • On a profile with the optimizer previously enabled, launching the app removes the __mcp-optimizer__ group, re-registers its clients to whichever group was in ALLOWED_GROUPS, and tears down the meta-mcp workload — before any user interaction.
  • On a fresh profile with no optimizer state, the startup hook short-circuits after the daemon-ready wait and never writes to the API.
  • Relaunching the app is a no-op (the session flag short-circuits, and the group no longer exists either way).
  • No main-process changes beyond the feature-flag flip — cleanup runs entirely in the renderer against the public thv HTTP API, mirroring the experimental-toggle-off path.
  • Unit tests updated: use-cleanup-meta-optimizer.test.ts matches the call-time fetch model, flags.test.ts asserts isDisabled flags always return false, and the obsolete optimizer-specific permission-profile case is removed from orchestrate-run-local-server.test.tsx.
  • E2E coverage: e2e-tests/mcp-optimizer-startup-cleanup.spec.ts (backed by a reusable launchApp + thvFetch helper) runs two sessions against the same temporary userDataDir and asserts the optimizer group is gone, the client is re-registered to the custom group, and GET /workloads/toolhive-mcp-optimizer returns 404.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions