"use client"; import { useState, useEffect, useRef } from "react"; import { Plug, ChevronDown, X, Zap } from "lucide-react"; interface MCPForChat { mcpId: string; name: string; toolCount: number; tools: Array<{ name: string; description: string }>; } interface MCPSelectorProps { activeMcps: string[]; onToggleMCP: (mcpId: string) => void; onClearAll: () => void; onOpenInstallModal?: () => void; } export function MCPSelector({ activeMcps, onToggleMCP, onClearAll, onOpenInstallModal, }: MCPSelectorProps) { const [isOpen, setIsOpen] = useState(false); const [availableMcps, setAvailableMcps] = useState([]); const [loading, setLoading] = useState(false); const [query, setQuery] = useState(""); const dropdownRef = useRef(null); // Carregar MCPs disponíveis useEffect(() => { if (isOpen) { loadAvailableMCPs(); } }, [isOpen]); // Fechar dropdown ao clicar fora useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( dropdownRef.current && !dropdownRef.current.contains(event.target as Node) ) { setIsOpen(false); } }; if (isOpen) { document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; } }, [isOpen]); const loadAvailableMCPs = async () => { setLoading(true); try { const response = await fetch("/api/mcp/available-for-chat"); const data = await response.json(); if (data.success) { setAvailableMcps( data.mcps.map((mcp: any) => ({ mcpId: mcp.mcpId, name: mcp.name, toolCount: mcp.toolCount, tools: mcp.rawTools || [], })) ); } } catch (error) { console.error("Error loading available MCPs:", error); } finally { setLoading(false); } }; const handleToggle = (mcpId: string) => { onToggleMCP(mcpId); }; const filtered = availableMcps.filter((mcp) => { if (!query.trim()) return true; const q = query.toLowerCase(); return ( mcp.name.toLowerCase().includes(q) || mcp.tools.some( (t) => t.name.toLowerCase().includes(q) || (t.description || "").toLowerCase().includes(q) ) ); }); return (
{/* Button */} {/* Dropdown */} {isOpen && (
{/* Header */}
MCP Tools
{activeMcps.length > 0 && ( )}
setQuery(e.target.value)} placeholder="Buscar por servidor ou ferramenta..." className="w-full px-3 py-2 text-sm rounded-md bg-[var(--background)] border border-[var(--border)] outline-none focus:border-[var(--accent)] transition-colors" />
{/* Content */}
{loading ? (
Carregando MCPs...
) : availableMcps.length === 0 ? (
Nenhum MCP instalado {onOpenInstallModal && (
)}
) : filtered.length === 0 ? (
Nenhum resultado para "{query}"
) : (
{filtered.map((mcp) => { const isActive = activeMcps.includes(mcp.mcpId); return (
handleToggle(mcp.mcpId)} >
{}} className="rounded" /> {mcp.name}
{mcp.toolCount} ferramentas disponíveis
{isActive && mcp.tools.length > 0 && (
{mcp.tools.slice(0, 3).map((tool, idx) => ( {tool.name} ))} {mcp.tools.length > 3 && ( +{mcp.tools.length - 3} )}
)}
); })}
)}
{/* Footer info */}

{activeMcps.length > 0 ? `${activeMcps.length} MCPs ativos para enriquecer as respostas` : "Nenhum MCP ativo"}

{onOpenInstallModal && ( )}
)}
); } /** * Pills/badges component to show active MCPs in the chat input area */ interface ActiveMCPBadgesProps { activeMcps: string[]; mcpNames: Map; onRemove: (mcpId: string) => void; } export function ActiveMCPBadges({ activeMcps, mcpNames, onRemove, }: ActiveMCPBadgesProps) { if (activeMcps.length === 0) return null; return (
{activeMcps.map((mcpId) => (
{mcpNames.get(mcpId) || mcpId}
))}
); }