From 733d2a6e6ecb325729d7b2258da4b7285b8bcebe Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Tue, 12 Nov 2024 13:32:12 +0000 Subject: [PATCH 1/6] Separate error states per tab Resolves #40. --- client/src/App.tsx | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index e90090fcb..33e272660 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -79,7 +79,11 @@ const App = () => { const [tools, setTools] = useState([]); const [toolResult, setToolResult] = useState(null); - const [error, setError] = useState(null); + const [errors, setErrors] = useState>({ + resources: null, + prompts: null, + tools: null, + }); const [command, setCommand] = useState(() => { return localStorage.getItem("lastCommand") || "mcp-server-everything"; }); @@ -175,17 +179,19 @@ const App = () => { const makeRequest = async >( request: ClientRequest, schema: T, + tabKey: keyof typeof errors ) => { if (!mcpClient) { throw new Error("MCP client not connected"); } - + try { const response = await mcpClient.request(request, schema); pushHistory(request, response); + setErrors(prev => ({ ...prev, [tabKey]: null })); return response; } catch (e: unknown) { - setError((e as Error).message); + setErrors(prev => ({ ...prev, [tabKey]: (e as Error).message })); throw e; } }; @@ -211,11 +217,12 @@ const App = () => { params: nextResourceCursor ? { cursor: nextResourceCursor } : {}, }, ListResourcesResultSchema, + 'resources' ); setResources(resources.concat(response.resources ?? [])); setNextResourceCursor(response.nextCursor); }; - + const listResourceTemplates = async () => { const response = await makeRequest( { @@ -225,13 +232,14 @@ const App = () => { : {}, }, ListResourceTemplatesResultSchema, + 'resources' ); setResourceTemplates( resourceTemplates.concat(response.resourceTemplates ?? []), ); setNextResourceTemplateCursor(response.nextCursor); }; - + const readResource = async (uri: string) => { const response = await makeRequest( { @@ -239,6 +247,7 @@ const App = () => { params: { uri }, }, ReadResourceResultSchema, + 'resources' ); setResourceContent(JSON.stringify(response, null, 2)); }; @@ -250,11 +259,12 @@ const App = () => { params: nextPromptCursor ? { cursor: nextPromptCursor } : {}, }, ListPromptsResultSchema, + 'prompts' ); setPrompts(response.prompts); setNextPromptCursor(response.nextCursor); }; - + const getPrompt = async (name: string, args: Record = {}) => { const response = await makeRequest( { @@ -262,6 +272,7 @@ const App = () => { params: { name, arguments: args }, }, GetPromptResultSchema, + 'prompts' ); setPromptContent(JSON.stringify(response, null, 2)); }; @@ -273,11 +284,12 @@ const App = () => { params: nextToolCursor ? { cursor: nextToolCursor } : {}, }, ListToolsResultSchema, + 'tools' ); setTools(response.tools); setNextToolCursor(response.nextCursor); }; - + const callTool = async (name: string, params: Record) => { const response = await makeRequest( { @@ -291,6 +303,7 @@ const App = () => { }, }, CompatibilityCallToolResultSchema, + 'tools' ); setToolResult(response); }; @@ -515,7 +528,7 @@ const App = () => { resourceContent={resourceContent} nextCursor={nextResourceCursor} nextTemplateCursor={nextResourceTemplateCursor} - error={error} + error={errors.resources} /> { setSelectedPrompt={setSelectedPrompt} promptContent={promptContent} nextCursor={nextPromptCursor} - error={error} + error={errors.prompts} /> - { }} toolResult={toolResult} nextCursor={nextToolCursor} - error={error} + error={errors.tools} /> Date: Tue, 12 Nov 2024 13:33:52 +0000 Subject: [PATCH 2/6] Remove unused `RequestsTab` --- client/src/App.tsx | 23 +++++++++--------- client/src/components/RequestsTabs.tsx | 33 -------------------------- 2 files changed, 11 insertions(+), 45 deletions(-) delete mode 100644 client/src/components/RequestsTabs.tsx diff --git a/client/src/App.tsx b/client/src/App.tsx index 33e272660..186c0c853 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,8 +1,10 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { - CompatibilityCallToolResultSchema, + ClientNotification, ClientRequest, + CompatibilityCallToolResult, + CompatibilityCallToolResultSchema, CreateMessageRequestSchema, CreateMessageResult, EmptyResultSchema, @@ -19,8 +21,6 @@ import { Root, ServerNotification, Tool, - CompatibilityCallToolResult, - ClientNotification, } from "@modelcontextprotocol/sdk/types.js"; import { useEffect, useRef, useState } from "react"; // Add dark mode class based on system preference @@ -40,16 +40,16 @@ import { import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Bell, + ChevronDown, + ChevronRight, Files, + FolderTree, Hammer, Hash, MessageSquare, Play, Send, Terminal, - FolderTree, - ChevronDown, - ChevronRight, } from "lucide-react"; import { ZodType } from "zod"; @@ -58,7 +58,6 @@ import ConsoleTab from "./components/ConsoleTab"; import HistoryAndNotifications from "./components/History"; import PingTab from "./components/PingTab"; import PromptsTab, { Prompt } from "./components/PromptsTab"; -import RequestsTab from "./components/RequestsTabs"; import ResourcesTab from "./components/ResourcesTab"; import RootsTab from "./components/RootsTab"; import SamplingTab, { PendingRequest } from "./components/SamplingTab"; @@ -184,7 +183,7 @@ const App = () => { if (!mcpClient) { throw new Error("MCP client not connected"); } - + try { const response = await mcpClient.request(request, schema); pushHistory(request, response); @@ -222,7 +221,7 @@ const App = () => { setResources(resources.concat(response.resources ?? [])); setNextResourceCursor(response.nextCursor); }; - + const listResourceTemplates = async () => { const response = await makeRequest( { @@ -239,7 +238,7 @@ const App = () => { ); setNextResourceTemplateCursor(response.nextCursor); }; - + const readResource = async (uri: string) => { const response = await makeRequest( { @@ -264,7 +263,7 @@ const App = () => { setPrompts(response.prompts); setNextPromptCursor(response.nextCursor); }; - + const getPrompt = async (name: string, args: Record = {}) => { const response = await makeRequest( { @@ -289,7 +288,7 @@ const App = () => { setTools(response.tools); setNextToolCursor(response.nextCursor); }; - + const callTool = async (name: string, params: Record) => { const response = await makeRequest( { diff --git a/client/src/components/RequestsTabs.tsx b/client/src/components/RequestsTabs.tsx deleted file mode 100644 index e6326d533..000000000 --- a/client/src/components/RequestsTabs.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { TabsContent } from "@/components/ui/tabs"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; -import { Send } from "lucide-react"; - -const RequestsTab = () => ( - -
-
-
- - -
-