import React, { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Wrench, Search, ToggleLeft, ToggleRight, Play, ChevronDown, ChevronUp, Clock, Hash, } from 'lucide-react'; import { Card, CardHeader, CardContent } from '@/components/ui/Card'; import { Button } from '@/components/ui/Button'; import { Badge } from '@/components/ui/Badge'; import { Input } from '@/components/ui/Input'; import { apiClient } from '@/api/client'; import { formatTimestamp } from '@/utils/helpers'; import type { MCPTool } from '@/types'; interface ToolRegistryProps { className?: string; } interface ToolCardProps { tool: MCPTool; onToggle: (enabled: boolean) => void; onExecute: (params: Record) => void; isToggling: boolean; } const ToolCard: React.FC = ({ tool, onToggle, onExecute, isToggling, }) => { const [isExpanded, setIsExpanded] = useState(false); const categoryColors: Record = { browser: 'text-blue-400 bg-blue-400/10', extraction: 'text-purple-400 bg-purple-400/10', navigation: 'text-green-400 bg-green-400/10', validation: 'text-orange-400 bg-orange-400/10', utility: 'text-gray-400 bg-gray-400/10', }; return (
{tool.name} {tool.enabled ? 'Enabled' : 'Disabled'}

{tool.description}

{tool.category}
{tool.usageCount}
{tool.lastUsed && (
{formatTimestamp(tool.lastUsed)}
)}
{isExpanded && (
Input Schema
{JSON.stringify(tool.inputSchema, null, 2)}
)}
); }; export const ToolRegistry: React.FC = ({ className }) => { const queryClient = useQueryClient(); const [searchQuery, setSearchQuery] = useState(''); const [categoryFilter, setCategoryFilter] = useState(null); const { data: tools, isLoading } = useQuery({ queryKey: ['tools'], queryFn: () => apiClient.getTools(), }); const toggleMutation = useMutation({ mutationFn: ({ name, enabled }: { name: string; enabled: boolean }) => apiClient.toggleTool(name, enabled), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['tools'] }); }, }); const executeMutation = useMutation({ mutationFn: ({ name, params, }: { name: string; params: Record; }) => apiClient.executeTool(name, params), }); const categories = React.useMemo((): string[] => { if (!tools) return []; return [...new Set(tools.map((t) => t.category).filter((c): c is string => !!c))]; }, [tools]); const filteredTools = React.useMemo(() => { if (!tools) return []; return tools.filter((tool) => { const matchesSearch = !searchQuery || tool.name.toLowerCase().includes(searchQuery.toLowerCase()) || tool.description.toLowerCase().includes(searchQuery.toLowerCase()); const matchesCategory = !categoryFilter || tool.category === categoryFilter; return matchesSearch && matchesCategory; }); }, [tools, searchQuery, categoryFilter]); const enabledCount = tools?.filter((t) => t.enabled).length ?? 0; return ( } /> {/* Search & Filter */}
setSearchQuery(e.target.value)} leftIcon={} className="flex-1" />
{/* Category Pills */}
{categories.map((cat: string) => ( ))}
{/* Tools List */}
{isLoading ? (
) : filteredTools.length === 0 ? (

No tools found

) : ( filteredTools.map((tool) => ( toggleMutation.mutate({ name: tool.name, enabled }) } onExecute={(params) => executeMutation.mutate({ name: tool.name, params }) } isToggling={toggleMutation.isPending} /> )) )}
{/* Execution Result */} {executeMutation.data !== undefined && (
Execution Result
{JSON.stringify(executeMutation.data, null, 2)}
)} {executeMutation.isError && (
{(executeMutation.error as Error).message}
)}
); }; export default ToolRegistry;