import { useCallback, useEffect, useRef, useState, useTransition } from "react"; import { getTemplate } from "./utils"; import { useMcpStore } from "./state"; import { AppShell } from "ui/layouts/AppShell"; import { TbHistory, TbHistoryOff, TbRefresh } from "react-icons/tb"; import { IconButton } from "ui/components/buttons/IconButton"; import { JsonViewer, JsonViewerTabs, type JsonViewerTabsRef } from "ui/components/code/JsonViewer"; import { Field, Form } from "ui/components/form/json-schema-form"; import { Button } from "ui/components/buttons/Button"; import * as Formy from "ui/components/form/Formy"; import { appShellStore } from "ui/store"; import { Icon } from "ui/components/display/Icon"; import { useMcpClient } from "./hooks/use-mcp-client"; import { Tooltip } from "@mantine/core"; import { Link } from "ui/components/wouter/Link"; import { useParams } from "wouter"; export function Sidebar() { const client = useMcpClient(); const closeSidebar = appShellStore((store) => store.closeSidebar("default")); const tools = useMcpStore((state) => state.tools); const setTools = useMcpStore((state) => state.setTools); const [loading, setLoading] = useState(false); const [query, setQuery] = useState(""); const [error, setError] = useState(null); const scrollContainerRef = useRef(undefined!); const handleRefresh = useCallback(async () => { setLoading(true); setError(null); try { const res = await client.listTools(); if (res) setTools(res.tools); } catch (e) { console.error(e); setError(String(e)); } setLoading(false); }, []); useEffect(() => { handleRefresh().then(() => { if (scrollContainerRef.current) { const selectedTool = scrollContainerRef.current.querySelector(".active"); if (selectedTool) { selectedTool.scrollIntoView({ behavior: "smooth", block: "center" }); } } }); }, []); return ( (
{error && ( )} {tools.length}
)} >
setQuery(e.target.value)} autoCapitalize="none" />
); } export function Content() { const { toolName } = useParams(); const tools = useMcpStore((state) => state.tools); const tool = tools.find((tool) => tool.name === toolName); const addHistory = useMcpStore((state) => state.addHistory); const [payload, setPayload] = useState(getTemplate(tool?.inputSchema)); const [result, setResult] = useState(null); const historyVisible = useMcpStore((state) => state.historyVisible); const setHistoryVisible = useMcpStore((state) => state.setHistoryVisible); const client = useMcpClient(); const jsonViewerTabsRef = useRef(null); const hasInputSchema = tool?.inputSchema && Object.keys(tool.inputSchema.properties ?? {}).length > 0; const [isPending, startTransition] = useTransition(); useEffect(() => { setPayload(getTemplate(tool?.inputSchema)); setResult(null); }, [toolName]); const handleSubmit = useCallback(async () => { if (!tool?.name) return; const request = { name: tool.name, arguments: payload, }; startTransition(async () => { addHistory("request", request); const res = await client.callTool(request); if (res) { setResult(res); addHistory("response", res); jsonViewerTabsRef.current?.setSelected("Result"); } }); }, [payload]); if (!tool) return null; let readableResult = result; try { readableResult = result ? (result as any).content?.[0].text ? JSON.parse((result as any).content[0].text) : result : null; } catch (e) {} return (
{ setPayload(value); }} onSubmit={handleSubmit} > setHistoryVisible(!historyVisible)} /> } > Tools / {" "} {tool?.name}

{tool?.description}

{hasInputSchema && }
{historyVisible && ( )}
); } const History = () => { const history = useMcpStore((state) => state.history.slice(0, 50)); return ( <> History
{history.map((item, i) => ( ))}
); };