{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "smithery-tool-card", "title": "Smithery Tool Card", "description": "A card component for displaying MCP tool information with click-to-open detail dialog.", "dependencies": ["ai", "lucide-react", "react-hook-form", "tokenx", "shiki"], "registryDependencies": [ "badge", "button", "card", "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(\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 & {\n\tcode: string;\n\tlanguage: BundledLanguage;\n\tshowLineNumbers?: boolean;\n};\n\ntype CodeBlockContextType = {\n\tcode: string;\n};\n\nconst CodeBlockContext = createContext({\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(\"\");\n\tconst [darkHtml, setDarkHtml] = useState(\"\");\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\n\t\t\t\n\t\t\t\t
\n\t\t\t\t\tpre]: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\tpre]: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
\n\t\t\t\t\t\t\t{children}\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\nexport type CodeBlockCopyButtonProps = ComponentProps & {\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\n\t\t\t{children ?? }\n\t\t\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 {\n\tCodeBlock,\n\tCodeBlockCopyButton,\n} from \"@/registry/new-york/smithery/code-block\";\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 { 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;\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) => Promise;\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(null);\n\tconst [error, setError] = useState(null);\n\tconst [executedAt, setExecutedAt] = useState(null);\n\tconst [activeTab, setActiveTab] = useState(\"code\");\n\tconst [estimatedTokens, setEstimatedTokens] = useState(null);\n\tconst [latency, setLatency] = useState(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>({\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) => {\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 = {};\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 = {};\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\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t{name}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t{tool.description && (\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t{tool.description}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t{tool.type && tool.type !== \"dynamic\" && (\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t{tool.type}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t)}\n\t\t\t\t\t
\n\t\t\t\t
\n\n\t\t\t\t
\n\t\t\t\t\t{/* Left Panel - Parameters */}\n\t\t\t\t\t
\n\t\t\t\t\t\t
\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
\n\t\t\t\t\t\t\t\t\t\t\t\t{label}\n\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{entries.map(([fieldName, property]) => (\n\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\t\t{fieldName}\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{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\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\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\n\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))}\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t
\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\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 && }\n\t\t\t\t\t\t\t\t\t\t\t{optionalSection}\n\t\t\t\t\t\t\t\t\t\t\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

\n\t\t\t\t\t\t\t\t\tThis tool has no parameters.\n\t\t\t\t\t\t\t\t

\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\n\t\t\t\t\t{/* Right Panel - Code & Output */}\n\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tCode\n\t\t\t\t\t\t\t\t\tOutput\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t 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\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\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\n\t\t\t\t\t\t\t\t{executedAt && estimatedTokens !== null && latency !== null && (\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t{executedAt.toLocaleTimeString()}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\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\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\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\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\t{isExecuting ? (\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t\tExecuting...\n\t\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t) : error ? (\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t{error}\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t) : result ? (\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\t\t
\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
\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\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\nfunction renderField(\n\tname: string,\n\tproperty: JSONSchemaProperty,\n\tregister: ReturnType[\"register\"],\n\tsetValue: ReturnType[\"setValue\"],\n\twatch: ReturnType[\"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 setValue(name, value)}\n\t\t\t>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t{property.enum.map((option) => (\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t{option}\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 boolean with Switch\n\tif (type === \"boolean\") {\n\t\tconst currentValue = watch(name);\n\t\treturn (\n\t\t\t
\n\t\t\t\t setValue(name, checked)}\n\t\t\t\t/>\n\t\t\t\t\n\t\t\t\t\t{currentValue ? \"Enabled\" : \"Disabled\"}\n\t\t\t\t\n\t\t\t
\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\n\t\t);\n\t}\n\n\t// Handle arrays\n\tif (type === \"array\") {\n\t\treturn (\n\t\t\t {\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 {\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\n\t\t);\n\t}\n\n\t// Default to regular Input for strings\n\treturn (\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,\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 {\n\tconst defaults: Record = {};\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" }, { "path": "registry/new-york/smithery/tool-card.tsx", "content": "\"use client\";\n\nimport type { Tool } from \"ai\";\nimport { ChevronRight } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Card, CardHeader } from \"@/components/ui/card\";\nimport { cn } from \"@/lib/utils\";\nimport { ToolDetailDialog } from \"@/registry/new-york/smithery/tool-detail-dialog\";\n\ninterface ToolCardProps {\n\tname: string;\n\ttool: Tool;\n\tonExecute?: (params: Record) => Promise;\n}\n\nexport function ToolCard({ name, tool, onExecute }: ToolCardProps) {\n\tconst [dialogOpen, setDialogOpen] = useState(false);\n\n\treturn (\n\t\t<>\n\t\t\t setDialogOpen(true)}\n\t\t\t>\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t

{name}

\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{tool.description && (\n\t\t\t\t\t\t\t\t

\n\t\t\t\t\t\t\t\t\t{tool.description}\n\t\t\t\t\t\t\t\t

\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t{tool.type && tool.type !== \"dynamic\" && (\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t{tool.type}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t)}\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t\n\n\t\t\t\n\t\t\n\t);\n}\n", "type": "registry:component", "target": "components/smithery/tool-card.tsx" } ], "type": "registry:block" }