'use client'; import React, { memo, useCallback } from 'react'; import { Handle, Position, type NodeProps } from '@xyflow/react'; import { Lock, Unlock } from 'lucide-react'; import type { ToolDefinition, AuthConfig } from '@mcpengine/ai-pipeline/types'; export interface ToolNodeData extends Record { tool: ToolDefinition; selected: boolean; enabled: boolean; onToggleEnabled?: (name: string) => void; } const methodColors: Record = { GET: { bg: 'bg-emerald-500/20', text: 'text-emerald-400' }, POST: { bg: 'bg-blue-500/20', text: 'text-blue-400' }, PUT: { bg: 'bg-amber-500/20', text: 'text-amber-400' }, PATCH: { bg: 'bg-orange-500/20', text: 'text-orange-400' }, DELETE: { bg: 'bg-red-500/20', text: 'text-red-400' }, }; function getParamCount(tool: ToolDefinition): number { return Object.keys(tool.inputSchema?.properties ?? {}).length; } function hasAuth(tool: ToolDefinition): boolean { // Infer auth from endpoint or annotations — the tool itself doesn't carry auth, // but we check if the method implies auth-required patterns return tool.endpoint?.includes('auth') || false; } export const ToolNode = memo(function ToolNode({ data, selected }: NodeProps) { const { tool, enabled = true, onToggleEnabled } = data as ToolNodeData; const method = (tool.method ?? 'GET').toUpperCase(); const colors = methodColors[method] ?? methodColors.GET; const paramCount = getParamCount(tool); const handleToggle = useCallback( (e: React.MouseEvent) => { e.stopPropagation(); onToggleEnabled?.(tool.name); }, [onToggleEnabled, tool.name] ); return (
{/* Target handle (top) */} {/* Method badge + name */}
{method} {tool.name}
{/* Description */}

{tool.description || 'No description'}

{/* Bottom row */}
{/* Param count badge */} {paramCount} param{paramCount !== 1 ? 's' : ''} {/* Auth indicator */} {hasAuth(tool) ? ( ) : ( )}
{/* Enabled/Disabled toggle */}
{/* Source handle (bottom) */}
); });