diff --git a/frontend/src/app/pages/Tools/Tools.tsx b/frontend/src/app/pages/Tools/Tools.tsx index 5c9a8323..13397e0b 100644 --- a/frontend/src/app/pages/Tools/Tools.tsx +++ b/frontend/src/app/pages/Tools/Tools.tsx @@ -462,7 +462,16 @@ const Tools: React.FC = () => { const { servers: regServersRaw, total: regTotal, loading: regLoading, stats: regStats, detail: regDetail, detailLoading: regDetailLoading } = useAppSelector((s) => s.mcpRegistry); const devMode = useAppSelector((s) => s.settings.data.dev_mode); const allTools = Object.values(items); - const tools = allTools; + // Deterministic order so cards don't jump around on refetch: connected + on first, then on, + // then anything toggled off (connection state ignored once it's off). A-Z within each tier. + const tools = useMemo(() => { + const tier = (t: ToolDefinition) => + t.enabled === false ? 2 : (t.auth_status === 'connected' ? 0 : 1); + return Object.values(items).sort((a, b) => { + const d = tier(a) - tier(b); + return d !== 0 ? d : (a.name || '').localeCompare(b.name || ''); + }); + }, [items]); const uninstalledIntegrations = useMemo(() => INTEGRATIONS.filter((ig) => !allTools.find((t) => t.name === ig.name)), [allTools]); const getIntegrationForTool = useCallback((tool: ToolDefinition) => INTEGRATIONS.find((ig) => ig.name === tool.name), []); @@ -1493,7 +1502,7 @@ const Tools: React.FC = () => { return (