{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "smithery-tool-detail-dialog",
	"title": "Smithery Tool Detail Dialog",
	"description": "A dialog component for viewing tool details, executing tools with parameters, and displaying code samples.",
	"dependencies": ["ai", "lucide-react", "react-hook-form", "tokenx", "shiki"],
	"registryDependencies": [
		"badge",
		"button",
		"dialog",
		"field",
		"input",
		"select",
		"switch",
		"tabs",
		"textarea"
	],
	"files": [
		{
			"path": "registry/new-york/smithery/connection-context.tsx",
			"content": "\"use client\";\n\nimport { createContext, useContext } from \"react\";\n\n// Context for connection config - consumed by ToolDetailDialog for code generation\nexport interface ConnectionConfig {\n\tmcpUrl: string;\n\tapiKey: string;\n\tnamespace: string;\n\tconnectionId: string;\n}\n\nexport const ConnectionConfigContext = createContext<ConnectionConfig | null>(\n\tnull,\n);\n\nexport function useConnectionConfig() {\n\treturn useContext(ConnectionConfigContext);\n}\n",
			"type": "registry:component",
			"target": "components/smithery/connection-context.tsx"
		},
		{
			"path": "registry/new-york/smithery/code-block.tsx",
			"content": "\"use client\";\n\nimport { CheckIcon, CopyIcon } from \"lucide-react\";\nimport {\n\ttype ComponentProps,\n\tcreateContext,\n\ttype HTMLAttributes,\n\tuseContext,\n\tuseEffect,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { type BundledLanguage, codeToHtml, type ShikiTransformer } from \"shiki\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\n\ntype CodeBlockProps = HTMLAttributes<HTMLDivElement> & {\n\tcode: string;\n\tlanguage: BundledLanguage;\n\tshowLineNumbers?: boolean;\n};\n\ntype CodeBlockContextType = {\n\tcode: string;\n};\n\nconst CodeBlockContext = createContext<CodeBlockContextType>({\n\tcode: \"\",\n});\n\nconst lineNumberTransformer: ShikiTransformer = {\n\tname: \"line-numbers\",\n\tline(node, line) {\n\t\tnode.children.unshift({\n\t\t\ttype: \"element\",\n\t\t\ttagName: \"span\",\n\t\t\tproperties: {\n\t\t\t\tclassName: [\n\t\t\t\t\t\"inline-block\",\n\t\t\t\t\t\"min-w-10\",\n\t\t\t\t\t\"mr-4\",\n\t\t\t\t\t\"text-right\",\n\t\t\t\t\t\"select-none\",\n\t\t\t\t\t\"text-muted-foreground\",\n\t\t\t\t],\n\t\t\t},\n\t\t\tchildren: [{ type: \"text\", value: String(line) }],\n\t\t});\n\t},\n};\n\nexport async function highlightCode(\n\tcode: string,\n\tlanguage: BundledLanguage,\n\tshowLineNumbers = false,\n) {\n\tconst transformers: ShikiTransformer[] = showLineNumbers\n\t\t? [lineNumberTransformer]\n\t\t: [];\n\n\treturn await Promise.all([\n\t\tcodeToHtml(code, {\n\t\t\tlang: language,\n\t\t\ttheme: \"one-light\",\n\t\t\ttransformers,\n\t\t}),\n\t\tcodeToHtml(code, {\n\t\t\tlang: language,\n\t\t\ttheme: \"one-dark-pro\",\n\t\t\ttransformers,\n\t\t}),\n\t]);\n}\n\nexport const CodeBlock = ({\n\tcode,\n\tlanguage,\n\tshowLineNumbers = false,\n\tclassName,\n\tchildren,\n\t...props\n}: CodeBlockProps) => {\n\tconst [html, setHtml] = useState<string>(\"\");\n\tconst [darkHtml, setDarkHtml] = useState<string>(\"\");\n\tconst mounted = useRef(false);\n\n\tuseEffect(() => {\n\t\thighlightCode(code, language, showLineNumbers).then(([light, dark]) => {\n\t\t\tif (!mounted.current) {\n\t\t\t\tsetHtml(light);\n\t\t\t\tsetDarkHtml(dark);\n\t\t\t\tmounted.current = true;\n\t\t\t}\n\t\t});\n\n\t\treturn () => {\n\t\t\tmounted.current = false;\n\t\t};\n\t}, [code, language, showLineNumbers]);\n\n\treturn (\n\t\t<CodeBlockContext.Provider value={{ code }}>\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"group relative w-full overflow-hidden rounded-md border bg-background text-foreground\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t<div className=\"relative\">\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"overflow-auto dark:hidden [&>pre]:m-0 [&>pre]:bg-background! [&>pre]:p-4 [&>pre]:text-foreground! [&>pre]:text-sm [&_code]:font-mono [&_code]:text-sm\"\n\t\t\t\t\t\t// biome-ignore lint/security/noDangerouslySetInnerHtml: \"this is needed.\"\n\t\t\t\t\t\tdangerouslySetInnerHTML={{ __html: html }}\n\t\t\t\t\t/>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"hidden overflow-auto dark:block [&>pre]:m-0 [&>pre]:bg-background! [&>pre]:p-4 [&>pre]:text-foreground! [&>pre]:text-sm [&_code]:font-mono [&_code]:text-sm\"\n\t\t\t\t\t\t// biome-ignore lint/security/noDangerouslySetInnerHtml: \"this is needed.\"\n\t\t\t\t\t\tdangerouslySetInnerHTML={{ __html: darkHtml }}\n\t\t\t\t\t/>\n\t\t\t\t\t{children && (\n\t\t\t\t\t\t<div className=\"absolute top-2 right-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t{children}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</CodeBlockContext.Provider>\n\t);\n};\n\nexport type CodeBlockCopyButtonProps = ComponentProps<typeof Button> & {\n\tonCopy?: () => void;\n\tonError?: (error: Error) => void;\n\ttimeout?: number;\n};\n\nexport const CodeBlockCopyButton = ({\n\tonCopy,\n\tonError,\n\ttimeout = 2000,\n\tchildren,\n\tclassName,\n\t...props\n}: CodeBlockCopyButtonProps) => {\n\tconst [isCopied, setIsCopied] = useState(false);\n\tconst { code } = useContext(CodeBlockContext);\n\n\tconst copyToClipboard = async () => {\n\t\tif (typeof window === \"undefined\" || !navigator?.clipboard?.writeText) {\n\t\t\tonError?.(new Error(\"Clipboard API not available\"));\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait navigator.clipboard.writeText(code);\n\t\t\tsetIsCopied(true);\n\t\t\tonCopy?.();\n\t\t\tsetTimeout(() => setIsCopied(false), timeout);\n\t\t} catch (error) {\n\t\t\tonError?.(error as Error);\n\t\t}\n\t};\n\n\tconst Icon = isCopied ? CheckIcon : CopyIcon;\n\n\treturn (\n\t\t<Button\n\t\t\tclassName={cn(\"shrink-0\", className)}\n\t\t\tonClick={copyToClipboard}\n\t\t\tsize=\"icon\"\n\t\t\tvariant=\"ghost\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children ?? <Icon size={14} />}\n\t\t</Button>\n\t);\n};\n",
			"type": "registry:component",
			"target": "components/smithery/code-block.tsx"
		},
		{
			"path": "registry/new-york/smithery/tool-detail-dialog.tsx",
			"content": "\"use client\";\n\nimport type { Tool } from \"ai\";\nimport { useEffect, useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { estimateTokenCount } from \"tokenx\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTitle,\n} from \"@/components/ui/dialog\";\nimport {\n\tField,\n\tFieldDescription,\n\tFieldError,\n\tFieldGroup,\n\tFieldLabel,\n\tFieldLegend,\n\tFieldSeparator,\n\tFieldSet,\n} from \"@/components/ui/field\";\nimport { Input } from \"@/components/ui/input\";\nimport {\n\tSelect,\n\tSelectContent,\n\tSelectItem,\n\tSelectTrigger,\n\tSelectValue,\n} from \"@/components/ui/select\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@/components/ui/tabs\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport {\n\tCodeBlock,\n\tCodeBlockCopyButton,\n} from \"@/registry/new-york/smithery/code-block\";\nimport { useConnectionConfig } from \"@/registry/new-york/smithery/connection-context\";\nimport { ToolOutputViewer } from \"@/registry/new-york/smithery/tool-output-viewer\";\n\ninterface JSONSchema {\n\ttype?: string;\n\tproperties?: Record<string, JSONSchemaProperty>;\n\trequired?: string[];\n\tadditionalProperties?: boolean;\n}\n\ninterface JSONSchemaProperty {\n\ttype?: string | string[];\n\tdescription?: string;\n\tenum?: string[];\n\tminimum?: number;\n\tmaximum?: number;\n\tdefault?: unknown;\n\titems?: JSONSchemaProperty;\n}\n\ninterface ToolDetailDialogProps {\n\topen: boolean;\n\tonOpenChange: (open: boolean) => void;\n\tname: string;\n\ttool: Tool;\n\tonExecute?: (params: Record<string, unknown>) => Promise<unknown>;\n}\n\nexport function ToolDetailDialog({\n\topen,\n\tonOpenChange,\n\tname,\n\ttool,\n\tonExecute,\n}: ToolDetailDialogProps) {\n\tconst connectionConfig = useConnectionConfig();\n\tconst [isExecuting, setIsExecuting] = useState(false);\n\tconst [result, setResult] = useState<unknown>(null);\n\tconst [error, setError] = useState<string | null>(null);\n\tconst [executedAt, setExecutedAt] = useState<Date | null>(null);\n\tconst [activeTab, setActiveTab] = useState(\"code\");\n\tconst [estimatedTokens, setEstimatedTokens] = useState<number | null>(null);\n\tconst [latency, setLatency] = useState<number | null>(null);\n\n\t// Extract schema\n\tconst inputSchema = tool.inputSchema;\n\tconst schema: JSONSchema =\n\t\ttypeof inputSchema === \"object\" &&\n\t\tinputSchema &&\n\t\t\"jsonSchema\" in inputSchema\n\t\t\t? (inputSchema as { jsonSchema: JSONSchema }).jsonSchema\n\t\t\t: (inputSchema as JSONSchema) || {};\n\n\tconst properties = schema.properties || {};\n\tconst requiredFields = schema.required || [];\n\tconst hasParameters = Object.keys(properties).length > 0;\n\n\tconst {\n\t\tregister,\n\t\thandleSubmit,\n\t\tformState: { errors },\n\t\tsetValue,\n\t\twatch,\n\t\treset,\n\t} = useForm<Record<string, unknown>>({\n\t\tdefaultValues: getDefaultValues(schema),\n\t});\n\n\tconst formValues = watch();\n\n\t// Reset form when dialog opens\n\tuseEffect(() => {\n\t\tif (open) {\n\t\t\treset(getDefaultValues(schema));\n\t\t\tsetResult(null);\n\t\t\tsetError(null);\n\t\t\tsetExecutedAt(null);\n\t\t\tsetActiveTab(\"code\");\n\t\t\tsetEstimatedTokens(null);\n\t\t\tsetLatency(null);\n\t\t}\n\t}, [open, reset, schema]);\n\n\t// Check if a value is empty and should be excluded\n\tconst isEmptyValue = (value: unknown): boolean => {\n\t\tif (value === \"\" || value === undefined || value === null) return true;\n\t\tif (typeof value === \"number\" && Number.isNaN(value)) return true;\n\t\tif (Array.isArray(value) && value.length === 0) return true;\n\t\tif (\n\t\t\ttypeof value === \"object\" &&\n\t\t\tvalue !== null &&\n\t\t\tObject.keys(value).length === 0\n\t\t)\n\t\t\treturn true;\n\t\treturn false;\n\t};\n\n\tconst handleExecuteSubmit = async (params: Record<string, unknown>) => {\n\t\tif (!onExecute) return;\n\n\t\t// Switch to output tab when execution starts\n\t\tsetActiveTab(\"output\");\n\t\tsetIsExecuting(true);\n\t\tsetError(null);\n\t\tsetResult(null);\n\t\tsetEstimatedTokens(null);\n\t\tsetLatency(null);\n\n\t\tconst startTime = performance.now();\n\n\t\ttry {\n\t\t\t// Parse JSON strings for arrays and objects, filter out empty values\n\t\t\tconst processedParams: Record<string, unknown> = {};\n\t\t\tfor (const [key, value] of Object.entries(params)) {\n\t\t\t\t// Try to parse JSON strings first\n\t\t\t\tlet parsedValue = value;\n\t\t\t\tif (\n\t\t\t\t\ttypeof value === \"string\" &&\n\t\t\t\t\t(value.startsWith(\"[\") || value.startsWith(\"{\"))\n\t\t\t\t) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tparsedValue = JSON.parse(value);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Keep original string if parsing fails\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Skip empty values\n\t\t\t\tif (isEmptyValue(parsedValue)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tprocessedParams[key] = parsedValue;\n\t\t\t}\n\n\t\t\tconst res = await onExecute(processedParams);\n\t\t\tconst endTime = performance.now();\n\t\t\tconst executionLatency = endTime - startTime;\n\n\t\t\t// Estimate token count of the result\n\t\t\tconst resultString = JSON.stringify(res);\n\t\t\tconst tokens = estimateTokenCount(resultString);\n\n\t\t\tsetResult(res);\n\t\t\tsetExecutedAt(new Date());\n\t\t\tsetLatency(executionLatency);\n\t\t\tsetEstimatedTokens(tokens);\n\t\t} catch (err) {\n\t\t\tsetError(err instanceof Error ? err.message : \"An error occurred\");\n\t\t} finally {\n\t\t\tsetIsExecuting(false);\n\t\t}\n\t};\n\n\t// Generate code preview\n\tconst generateCodePreview = () => {\n\t\tconst params: Record<string, unknown> = {};\n\t\tfor (const [key, value] of Object.entries(formValues)) {\n\t\t\t// Try to parse JSON strings first\n\t\t\tlet parsedValue = value;\n\t\t\tif (\n\t\t\t\ttypeof value === \"string\" &&\n\t\t\t\t(value.startsWith(\"[\") || value.startsWith(\"{\"))\n\t\t\t) {\n\t\t\t\ttry {\n\t\t\t\t\tparsedValue = JSON.parse(value);\n\t\t\t\t} catch {\n\t\t\t\t\t// Keep original string if parsing fails\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!isEmptyValue(parsedValue)) {\n\t\t\t\tparams[key] = parsedValue;\n\t\t\t}\n\t\t}\n\n\t\treturn generateToolExecuteCode(name, params, connectionConfig);\n\t};\n\n\treturn (\n\t\t<Dialog open={open} onOpenChange={onOpenChange}>\n\t\t\t<DialogContent className=\"!max-w-[75vw] !max-h-[85vh] overflow-hidden flex flex-col\">\n\t\t\t\t<DialogHeader>\n\t\t\t\t\t<div className=\"flex items-start justify-between gap-4 pr-8\">\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<DialogTitle className=\"text-lg font-semibold break-all\">\n\t\t\t\t\t\t\t\t{name}\n\t\t\t\t\t\t\t</DialogTitle>\n\t\t\t\t\t\t\t{tool.description && (\n\t\t\t\t\t\t\t\t<DialogDescription className=\"mt-1.5\">\n\t\t\t\t\t\t\t\t\t{tool.description}\n\t\t\t\t\t\t\t\t</DialogDescription>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{tool.type && tool.type !== \"dynamic\" && (\n\t\t\t\t\t\t\t<Badge variant=\"outline\" className=\"shrink-0\">\n\t\t\t\t\t\t\t\t{tool.type}\n\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</DialogHeader>\n\n\t\t\t\t<div className=\"flex-1 overflow-hidden grid grid-cols-1 md:grid-cols-5 gap-6 min-h-0\">\n\t\t\t\t\t{/* Left Panel - Parameters */}\n\t\t\t\t\t<div className=\"md:col-span-2 overflow-auto px-2\">\n\t\t\t\t\t\t<form id=\"tool-form\" onSubmit={handleSubmit(handleExecuteSubmit)}>\n\t\t\t\t\t\t\t{hasParameters ? (\n\t\t\t\t\t\t\t\t(() => {\n\t\t\t\t\t\t\t\t\tconst requiredEntries = Object.entries(properties).filter(\n\t\t\t\t\t\t\t\t\t\t([fieldName]) => requiredFields.includes(fieldName),\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tconst optionalEntries = Object.entries(properties).filter(\n\t\t\t\t\t\t\t\t\t\t([fieldName]) => !requiredFields.includes(fieldName),\n\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\tconst renderFieldSet = (\n\t\t\t\t\t\t\t\t\t\tentries: Array<[string, JSONSchemaProperty]>,\n\t\t\t\t\t\t\t\t\t\tisRequired: boolean,\n\t\t\t\t\t\t\t\t\t\tlabel: string,\n\t\t\t\t\t\t\t\t\t) => {\n\t\t\t\t\t\t\t\t\t\tif (entries.length === 0) return null;\n\n\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t<FieldSet>\n\t\t\t\t\t\t\t\t\t\t\t\t<FieldLegend>{label}</FieldLegend>\n\t\t\t\t\t\t\t\t\t\t\t\t<FieldGroup>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{entries.map(([fieldName, property]) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Field key={fieldName}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<FieldLabel htmlFor={fieldName}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{fieldName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</FieldLabel>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{renderField(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tproperty,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tregister,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetValue,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twatch,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisRequired,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{property.description && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<FieldDescription>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{property.description}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</FieldDescription>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<FieldError\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\terrors={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\terrors[fieldName]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? [errors[fieldName]]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Field>\n\t\t\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t\t\t</FieldGroup>\n\t\t\t\t\t\t\t\t\t\t\t</FieldSet>\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\tconst requiredSection = renderFieldSet(\n\t\t\t\t\t\t\t\t\t\trequiredEntries,\n\t\t\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\t\t\t\"Required\",\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tconst optionalSection = renderFieldSet(\n\t\t\t\t\t\t\t\t\t\toptionalEntries,\n\t\t\t\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t\t\t\t\t\"Optional\",\n\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<FieldGroup>\n\t\t\t\t\t\t\t\t\t\t\t{requiredSection}\n\t\t\t\t\t\t\t\t\t\t\t{requiredSection && optionalSection && <FieldSeparator />}\n\t\t\t\t\t\t\t\t\t\t\t{optionalSection}\n\t\t\t\t\t\t\t\t\t\t</FieldGroup>\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t})()\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">\n\t\t\t\t\t\t\t\t\tThis tool has no parameters.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</form>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{/* Right Panel - Code & Output */}\n\t\t\t\t\t<div className=\"md:col-span-3 overflow-hidden flex flex-col min-h-0\">\n\t\t\t\t\t\t<Tabs\n\t\t\t\t\t\t\tvalue={activeTab}\n\t\t\t\t\t\t\tonValueChange={setActiveTab}\n\t\t\t\t\t\t\tclassName=\"flex-1 flex flex-col min-h-0\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-between gap-2\">\n\t\t\t\t\t\t\t\t<TabsList className=\"w-fit\">\n\t\t\t\t\t\t\t\t\t<TabsTrigger value=\"code\">Code</TabsTrigger>\n\t\t\t\t\t\t\t\t\t<TabsTrigger value=\"output\">Output</TabsTrigger>\n\t\t\t\t\t\t\t\t</TabsList>\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tdisabled={isExecuting}\n\t\t\t\t\t\t\t\t\tonClick={() => handleSubmit(handleExecuteSubmit)()}\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{isExecuting ? \"Executing...\" : \"Execute\"}\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<TabsContent value=\"code\" className=\"flex-1 overflow-auto mt-3\">\n\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-3 h-full\">\n\t\t\t\t\t\t\t\t\t<CodeBlock\n\t\t\t\t\t\t\t\t\t\tcode=\"npm install @smithery/api @modelcontextprotocol/sdk\"\n\t\t\t\t\t\t\t\t\t\tlanguage=\"bash\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<CodeBlockCopyButton />\n\t\t\t\t\t\t\t\t\t</CodeBlock>\n\t\t\t\t\t\t\t\t\t<CodeBlock\n\t\t\t\t\t\t\t\t\t\tcode={generateCodePreview()}\n\t\t\t\t\t\t\t\t\t\tlanguage=\"typescript\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex-1 overflow-auto\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<CodeBlockCopyButton />\n\t\t\t\t\t\t\t\t\t</CodeBlock>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</TabsContent>\n\t\t\t\t\t\t\t<TabsContent\n\t\t\t\t\t\t\t\tvalue=\"output\"\n\t\t\t\t\t\t\t\tclassName=\"flex-1 overflow-auto mt-3 flex flex-col gap-3\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{executedAt && estimatedTokens !== null && latency !== null && (\n\t\t\t\t\t\t\t\t\t<div className=\"flex items-center gap-2 text-xs text-muted-foreground px-1\">\n\t\t\t\t\t\t\t\t\t\t<span>{executedAt.toLocaleTimeString()}</span>\n\t\t\t\t\t\t\t\t\t\t<span>•</span>\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">\n\t\t\t\t\t\t\t\t\t\t\t{estimatedTokens.toLocaleString()} tokens\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t<span>•</span>\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">\n\t\t\t\t\t\t\t\t\t\t\t{latency.toLocaleString()}ms\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{isExecuting ? (\n\t\t\t\t\t\t\t\t\t<div className=\"flex items-center justify-center h-full text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col items-center gap-2\">\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"animate-spin h-6 w-6 border-2 border-muted-foreground border-t-transparent rounded-full\" />\n\t\t\t\t\t\t\t\t\t\t\t<span>Executing...</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t) : error ? (\n\t\t\t\t\t\t\t\t\t<div className=\"rounded-md bg-destructive/10 p-4 text-sm text-destructive\">\n\t\t\t\t\t\t\t\t\t\t{error}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t) : result ? (\n\t\t\t\t\t\t\t\t\t<ToolOutputViewer result={result} />\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<div className=\"flex items-center justify-center h-full text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\t\tExecute the tool to see output\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</TabsContent>\n\t\t\t\t\t\t</Tabs>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t);\n}\n\nfunction renderField(\n\tname: string,\n\tproperty: JSONSchemaProperty,\n\tregister: ReturnType<typeof useForm>[\"register\"],\n\tsetValue: ReturnType<typeof useForm>[\"setValue\"],\n\twatch: ReturnType<typeof useForm>[\"watch\"],\n\tisRequired: boolean,\n) {\n\tconst type = Array.isArray(property.type) ? property.type[0] : property.type;\n\n\t// Handle enums with Select\n\tif (property.enum && property.enum.length > 0) {\n\t\tconst currentValue = watch(name);\n\t\treturn (\n\t\t\t<Select\n\t\t\t\tvalue={currentValue as string}\n\t\t\t\tonValueChange={(value) => setValue(name, value)}\n\t\t\t>\n\t\t\t\t<SelectTrigger className=\"w-full\" id={name}>\n\t\t\t\t\t<SelectValue placeholder=\"Select an option\" />\n\t\t\t\t</SelectTrigger>\n\t\t\t\t<SelectContent className=\"w-full\">\n\t\t\t\t\t{property.enum.map((option) => (\n\t\t\t\t\t\t<SelectItem key={option} value={option}>\n\t\t\t\t\t\t\t{option}\n\t\t\t\t\t\t</SelectItem>\n\t\t\t\t\t))}\n\t\t\t\t</SelectContent>\n\t\t\t</Select>\n\t\t);\n\t}\n\n\t// Handle boolean with Switch\n\tif (type === \"boolean\") {\n\t\tconst currentValue = watch(name);\n\t\treturn (\n\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t<Switch\n\t\t\t\t\tid={name}\n\t\t\t\t\tchecked={currentValue as boolean}\n\t\t\t\t\tonCheckedChange={(checked) => setValue(name, checked)}\n\t\t\t\t/>\n\t\t\t\t<span className=\"text-sm text-muted-foreground\">\n\t\t\t\t\t{currentValue ? \"Enabled\" : \"Disabled\"}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// Handle number with Input type number\n\tif (type === \"number\" || type === \"integer\") {\n\t\treturn (\n\t\t\t<Input\n\t\t\t\tid={name}\n\t\t\t\ttype=\"number\"\n\t\t\t\t{...register(name, {\n\t\t\t\t\trequired: isRequired ? `${name} is required` : false,\n\t\t\t\t\tvalueAsNumber: true,\n\t\t\t\t\tmin: property.minimum,\n\t\t\t\t\tmax: property.maximum,\n\t\t\t\t})}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// Handle arrays\n\tif (type === \"array\") {\n\t\treturn (\n\t\t\t<Textarea\n\t\t\t\tid={name}\n\t\t\t\tplaceholder=\"Enter JSON array (e.g., [1, 2, 3])\"\n\t\t\t\t{...register(name, {\n\t\t\t\t\trequired: isRequired ? `${name} is required` : false,\n\t\t\t\t\tvalidate: (value) => {\n\t\t\t\t\t\tif (!value) return true;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst parsed = JSON.parse(value as string);\n\t\t\t\t\t\t\treturn Array.isArray(parsed) || \"Must be a valid JSON array\";\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn \"Must be valid JSON\";\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t})}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// Handle objects\n\tif (type === \"object\") {\n\t\treturn (\n\t\t\t<Textarea\n\t\t\t\tid={name}\n\t\t\t\tplaceholder='Enter JSON object (e.g., {\"key\": \"value\"})'\n\t\t\t\t{...register(name, {\n\t\t\t\t\trequired: isRequired ? `${name} is required` : false,\n\t\t\t\t\tvalidate: (value) => {\n\t\t\t\t\t\tif (!value) return true;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst parsed = JSON.parse(value as string);\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\ttypeof parsed === \"object\" || \"Must be a valid JSON object\"\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn \"Must be valid JSON\";\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t})}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// Handle string - use Textarea if description suggests long text\n\tconst useLongText =\n\t\tproperty.description?.toLowerCase().includes(\"description\") ||\n\t\tproperty.description?.toLowerCase().includes(\"long\") ||\n\t\tproperty.description?.toLowerCase().includes(\"paragraph\");\n\n\tif (useLongText) {\n\t\treturn (\n\t\t\t<Textarea\n\t\t\t\tid={name}\n\t\t\t\t{...register(name, {\n\t\t\t\t\trequired: isRequired ? `${name} is required` : false,\n\t\t\t\t})}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// Default to regular Input for strings\n\treturn (\n\t\t<Input\n\t\t\tid={name}\n\t\t\ttype=\"text\"\n\t\t\t{...register(name, {\n\t\t\t\trequired: isRequired ? `${name} is required` : false,\n\t\t\t})}\n\t\t/>\n\t);\n}\n\ninterface ConnectionConfig {\n\tmcpUrl: string;\n\tapiKey: string;\n\tnamespace: string;\n\tconnectionId: string;\n}\n\nfunction generateToolExecuteCode(\n\ttoolName: string,\n\tparams: Record<string, unknown>,\n\tconfig: ConnectionConfig | null,\n): string {\n\tconst mcpUrl = config?.mcpUrl || \"process.env.MCP_URL\";\n\tconst _namespace = config?.namespace\n\t\t? `\"${config.namespace}\"`\n\t\t: \"process.env.SMITHERY_NAMESPACE\";\n\tconst connectionId = config?.connectionId\n\t\t? `\"${config.connectionId}\"`\n\t\t: \"connectionId\";\n\n\tconst code = `import { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport Smithery from '@smithery/api';\nimport { createConnection } from '@smithery/api/mcp';\n\nconst mcpUrl = \"${mcpUrl}\";\nconst connectionId = ${connectionId};\nconst apiKey = process.env.SMITHERY_API_KEY;\n\nconst { transport } = await createConnection({\n  client: new Smithery({ apiKey }),\n  connectionId,\n  mcpUrl,\n});\n\n// Initialize the Traditional MCP Client\nconst mcpClient = new Client({\n    name: \"smithery-mcp-client\",\n    version: \"1.0.0\",\n});\n\n// Connect explicitly\nawait mcpClient.connect(transport);\n\nconst result = await mcpClient.callTool({\n  name: \"${toolName}\",\n  arguments: ${JSON.stringify(params, null, 2)},\n});\nconsole.log(result);\n`;\n\n\treturn code.trim();\n}\n\nfunction getDefaultValues(schema: JSONSchema): Record<string, unknown> {\n\tconst defaults: Record<string, unknown> = {};\n\tconst properties = schema.properties || {};\n\n\tfor (const [name, property] of Object.entries(properties)) {\n\t\tif (property.default !== undefined) {\n\t\t\tdefaults[name] = property.default;\n\t\t} else {\n\t\t\tconst type = Array.isArray(property.type)\n\t\t\t\t? property.type[0]\n\t\t\t\t: property.type;\n\t\t\t// Set sensible defaults based on type\n\t\t\tif (type === \"boolean\") {\n\t\t\t\tdefaults[name] = false;\n\t\t\t} else if (type === \"number\" || type === \"integer\") {\n\t\t\t\tdefaults[name] = \"\";\n\t\t\t} else if (type === \"array\") {\n\t\t\t\tdefaults[name] = \"\";\n\t\t\t} else if (type === \"object\") {\n\t\t\t\tdefaults[name] = \"\";\n\t\t\t} else {\n\t\t\t\tdefaults[name] = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\treturn defaults;\n}\n",
			"type": "registry:component",
			"target": "components/smithery/tool-detail-dialog.tsx"
		}
	],
	"type": "registry:block"
}
