import React, { memo, useMemo, useCallback, useRef } from 'react'; import * as Ariakit from '@ariakit/react'; import { ChevronDown } from 'lucide-react'; import { PermissionTypes, Permissions } from 'librechat-data-provider'; import { TooltipAnchor } from '@librechat/client'; import MCPServerMenuItem from '~/components/MCP/MCPServerMenuItem'; import MCPConfigDialog from '~/components/MCP/MCPConfigDialog'; import StackedMCPIcons from '~/components/MCP/StackedMCPIcons'; import { useBadgeRowContext } from '~/Providers'; import { useHasAccess } from '~/hooks'; import { cn } from '~/utils'; function MCPSelectContent() { const { conversationId, mcpServerManager } = useBadgeRowContext(); const { localize, isPinned, mcpValues, placeholderText, selectableServers, connectionStatus, isInitializing, getConfigDialogProps, toggleServerSelection, getServerStatusIconProps, } = mcpServerManager; const menuStore = Ariakit.useMenuStore({ focusLoop: true }); const isOpen = menuStore.useState('open'); const focusedElementRef = useRef(null); const selectedCount = mcpValues?.length ?? 0; // Wrap toggleServerSelection to preserve focus after state update const handleToggle = useCallback( (serverName: string) => { // Save currently focused element focusedElementRef.current = document.activeElement as HTMLElement; toggleServerSelection(serverName); // Restore focus after React re-renders requestAnimationFrame(() => { focusedElementRef.current?.focus(); }); }, [toggleServerSelection], ); const selectedServers = useMemo(() => { if (!mcpValues || mcpValues.length === 0) { return []; } return selectableServers.filter((s) => mcpValues.includes(s.serverName)); }, [selectableServers, mcpValues]); const displayText = useMemo(() => { if (selectedCount === 0) { return null; } if (selectedCount === 1) { const server = selectableServers.find((s) => s.serverName === mcpValues?.[0]); return server?.config?.title || mcpValues?.[0]; } return localize('com_ui_x_selected', { 0: selectedCount }); }, [selectedCount, selectableServers, mcpValues, localize]); if (!isPinned && mcpValues?.length === 0) { return null; } const configDialogProps = getConfigDialogProps(); return ( <> } > {displayText || placeholderText}
{selectableServers.map((server) => ( ))}
{configDialogProps && ( )} ); } function MCPSelect() { const { mcpServerManager } = useBadgeRowContext(); const { selectableServers } = mcpServerManager; const canUseMcp = useHasAccess({ permissionType: PermissionTypes.MCP_SERVERS, permission: Permissions.USE, }); if (!canUseMcp || !selectableServers || selectableServers.length === 0) { return null; } return ; } export default memo(MCPSelect);