import { useState, useEffect } from 'react' import { Wrench, Play, Circle, CircleDot, Code2, FileJson, RefreshCw } from 'lucide-react' import { Button } from './Button' import type { Tool } from '../App' import './ToolsPanel.css' interface ToolsPanelProps { tools: Tool[] selectedTool: Tool | null onSelectTool: (tool: Tool | null) => void onExecuteTool: (toolName: string, params: Record) => void onRefreshTools: () => void isConnected: boolean isExecuting: boolean isRefreshing: boolean } export function ToolsPanel({ tools, selectedTool, onSelectTool, onExecuteTool, onRefreshTools, isConnected, isExecuting, isRefreshing }: ToolsPanelProps) { const [params, setParams] = useState>({}) const [jsonMode, setJsonMode] = useState(false) const [jsonInput, setJsonInput] = useState('{}') // Build initial params for a tool (string values for form state) const buildInitialParams = (tool: Tool): Record => { const initialParams: Record = {} const props = tool.inputSchema?.properties || {} for (const [key, value] of Object.entries(props)) { if (value.default !== undefined) { initialParams[key] = typeof value.default === 'string' ? value.default : JSON.stringify(value.default) } else { initialParams[key] = '' } } return initialParams } // Convert string params to typed params for execution const buildExecuteParams = (tool: Tool, stringParams: Record): Record => { const finalParams: Record = {} const props = tool.inputSchema?.properties || {} for (const [key, value] of Object.entries(stringParams)) { const propType = props[key]?.type // Skip empty optional fields (but always include if there's a value or it's required) const isRequired = tool.inputSchema?.required?.includes(key) if (!value && !isRequired && !props[key]?.default) continue // Try to parse as JSON for arrays/objects if (value && (value.startsWith('[') || value.startsWith('{'))) { try { finalParams[key] = JSON.parse(value) continue } catch { // Fall through to string } } // Convert to appropriate type if (propType === 'number' || propType === 'integer') { finalParams[key] = value ? Number(value) : undefined } else if (propType === 'boolean') { finalParams[key] = value === 'true' } else { finalParams[key] = value } } return finalParams } // Reset params when tool changes useEffect(() => { if (selectedTool) { const initialParams = buildInitialParams(selectedTool) setParams(initialParams) setJsonInput(JSON.stringify(initialParams, null, 2)) } }, [selectedTool]) // Handle tool click - select and execute with defaults const handleToolClick = (tool: Tool) => { onSelectTool(tool) const initialParams = buildInitialParams(tool) const executeParams = buildExecuteParams(tool, initialParams) onExecuteTool(tool.name, executeParams) } const handleExecute = () => { if (!selectedTool) return let finalParams: Record = {} if (jsonMode) { try { finalParams = JSON.parse(jsonInput) } catch { alert('Invalid JSON') return } } else { finalParams = buildExecuteParams(selectedTool, params) } onExecuteTool(selectedTool.name, finalParams) } const renderParamInput = (name: string, schema: { type?: string description?: string default?: unknown enum?: string[] } | undefined) => { if (schema?.enum) { return ( ) } const isArray = schema?.type === 'array' return ( setParams({ ...params, [name]: e.target.value })} placeholder={isArray ? '["item1", "item2"]' : schema?.type || 'string'} /> ) } return (
Tools {tools.length} {isConnected && ( )}
{!isConnected ? (

Connect to a server to view available tools

) : tools.length === 0 ? (

No tools available

) : (
{tools.map((tool) => ( ))}
{selectedTool && (

{selectedTool.name}

{selectedTool.description && (

{selectedTool.description}

)}
Parameters
{jsonMode ? (