From 718bd10db168274a3e7e15a9cfcc4cd22fd4e458 Mon Sep 17 00:00:00 2001 From: Jesse Lumarie Date: Thu, 28 Aug 2025 13:05:12 -0600 Subject: [PATCH] mcp: add icon + website for testing SEP-974 --- cli/package.json | 2 +- client/package.json | 2 +- client/src/App.tsx | 2 + client/src/__tests__/App.routing.test.tsx | 1 + client/src/components/IconDisplay.tsx | 57 +++++++++++++++++++++++ client/src/components/PromptsTab.tsx | 18 +++++-- client/src/components/ResourcesTab.tsx | 57 ++++++++++++++++++----- client/src/components/Sidebar.tsx | 45 ++++++++++++++++++ client/src/components/ToolsTab.tsx | 20 ++++++-- client/src/lib/hooks/useConnection.ts | 10 ++++ package.json | 2 +- 11 files changed, 193 insertions(+), 23 deletions(-) create mode 100644 client/src/components/IconDisplay.tsx diff --git a/cli/package.json b/cli/package.json index 506b18564..5a888ac1e 100644 --- a/cli/package.json +++ b/cli/package.json @@ -24,7 +24,7 @@ }, "devDependencies": {}, "dependencies": { - "@modelcontextprotocol/sdk": "^1.17.5", + "@modelcontextprotocol/sdk": "file:../../typescript-sdk", "commander": "^13.1.0", "spawn-rx": "^5.1.2" } diff --git a/client/package.json b/client/package.json index 61f65b623..60798fe51 100644 --- a/client/package.json +++ b/client/package.json @@ -25,7 +25,7 @@ "cleanup:e2e": "node e2e/global-teardown.js" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.17.5", + "@modelcontextprotocol/sdk": "file:../../typescript-sdk", "@radix-ui/react-checkbox": "^1.1.4", "@radix-ui/react-dialog": "^1.1.3", "@radix-ui/react-icons": "^1.3.0", diff --git a/client/src/App.tsx b/client/src/App.tsx index fecd98399..b707b00ce 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -198,6 +198,7 @@ const App = () => { const { connectionStatus, serverCapabilities, + serverImplementation, mcpClient, requestHistory, makeRequest, @@ -818,6 +819,7 @@ const App = () => { logLevel={logLevel} sendLogLevelRequest={sendLogLevelRequest} loggingSupported={!!serverCapabilities?.logging || false} + serverImplementation={serverImplementation} />
({ const disconnectedConnectionState = { connectionStatus: "disconnected" as const, serverCapabilities: null, + serverImplementation: null, mcpClient: null, requestHistory: [], makeRequest: jest.fn(), diff --git a/client/src/components/IconDisplay.tsx b/client/src/components/IconDisplay.tsx new file mode 100644 index 000000000..33e405914 --- /dev/null +++ b/client/src/components/IconDisplay.tsx @@ -0,0 +1,57 @@ +// Define Icon type locally since it might not be exported yet +interface Icon { + src: string; + mimeType?: string; + sizes?: string; +} + +// Helper type for objects that may have icons +export interface WithIcons { + icons?: Icon[]; +} + +interface IconDisplayProps { + icons?: Icon[]; + className?: string; + size?: "sm" | "md" | "lg"; +} + +const IconDisplay = ({ + icons, + className = "", + size = "md", +}: IconDisplayProps) => { + if (!icons || icons.length === 0) { + return null; + } + + const sizeClasses = { + sm: "w-4 h-4", + md: "w-6 h-6", + lg: "w-8 h-8", + }; + + const sizeClass = sizeClasses[size]; + + return ( +
+ {icons.map((icon, index) => ( + { + // Hide broken images + e.currentTarget.style.display = "none"; + }} + /> + ))} +
+ ); +}; + +export default IconDisplay; diff --git a/client/src/components/PromptsTab.tsx b/client/src/components/PromptsTab.tsx index fa5905580..8f53a0a74 100644 --- a/client/src/components/PromptsTab.tsx +++ b/client/src/components/PromptsTab.tsx @@ -14,6 +14,7 @@ import { useEffect, useState } from "react"; import ListPane from "./ListPane"; import { useCompletionState } from "@/lib/hooks/useCompletionState"; import JsonView from "./JsonView"; +import IconDisplay from "./IconDisplay"; export type Prompt = { name: string; @@ -23,6 +24,7 @@ export type Prompt = { description?: string; required?: boolean; }[]; + icons?: { src: string; mimeType?: string; sizes?: string }[]; }; const PromptsTab = ({ @@ -101,7 +103,10 @@ const PromptsTab = ({ }} renderItem={(prompt) => (
- {prompt.name} +
+ + {prompt.name} +
{prompt.description} @@ -114,9 +119,14 @@ const PromptsTab = ({
-

- {selectedPrompt ? selectedPrompt.name : "Select a prompt"} -

+
+ {selectedPrompt && ( + + )} +

+ {selectedPrompt ? selectedPrompt.name : "Select a prompt"} +

+
{error ? ( diff --git a/client/src/components/ResourcesTab.tsx b/client/src/components/ResourcesTab.tsx index 874e0ff7d..969712edc 100644 --- a/client/src/components/ResourcesTab.tsx +++ b/client/src/components/ResourcesTab.tsx @@ -17,6 +17,7 @@ import { useEffect, useState } from "react"; import { useCompletionState } from "@/lib/hooks/useCompletionState"; import JsonView from "./JsonView"; import { UriTemplate } from "@modelcontextprotocol/sdk/shared/uriTemplate.js"; +import IconDisplay, { WithIcons } from "./IconDisplay"; const ResourcesTab = ({ resources, @@ -129,7 +130,16 @@ const ResourcesTab = ({ }} renderItem={(resource) => (
- + {(resource as WithIcons).icons && + (resource as WithIcons).icons!.length > 0 ? ( + + ) : ( + + )} {resource.name} @@ -159,7 +169,16 @@ const ResourcesTab = ({ }} renderItem={(template) => (
- + {(template as WithIcons).icons && + (template as WithIcons).icons!.length > 0 ? ( + + ) : ( + + )} {template.name} @@ -175,16 +194,30 @@ const ResourcesTab = ({
-

- {selectedResource - ? selectedResource.name - : selectedTemplate - ? selectedTemplate.name - : "Select a resource or template"} -

+
+ {selectedResource && (selectedResource as WithIcons).icons && ( + + )} + {selectedTemplate && (selectedTemplate as WithIcons).icons && ( + + )} +

+ {selectedResource + ? selectedResource.name + : selectedTemplate + ? selectedTemplate.name + : "Select a resource or template"} +

+
{selectedResource && (
{resourceSubscriptionsSupported && diff --git a/client/src/components/Sidebar.tsx b/client/src/components/Sidebar.tsx index a44c6e299..da81fb0fe 100644 --- a/client/src/components/Sidebar.tsx +++ b/client/src/components/Sidebar.tsx @@ -14,6 +14,7 @@ import { RefreshCwOff, Copy, CheckCheck, + Server, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -38,6 +39,7 @@ import { TooltipContent, } from "@/components/ui/tooltip"; import { useToast } from "../lib/hooks/useToast"; +import IconDisplay, { WithIcons } from "./IconDisplay"; interface SidebarProps { connectionStatus: ConnectionStatus; @@ -66,6 +68,9 @@ interface SidebarProps { loggingSupported: boolean; config: InspectorConfig; setConfig: (config: InspectorConfig) => void; + serverImplementation?: + | (WithIcons & { name?: string; version?: string; websiteUrl?: string }) + | null; } const Sidebar = ({ @@ -95,6 +100,7 @@ const Sidebar = ({ loggingSupported, config, setConfig, + serverImplementation, }: SidebarProps) => { const [theme, setTheme] = useTheme(); const [showEnvVars, setShowEnvVars] = useState(false); @@ -729,6 +735,45 @@ const Sidebar = ({
+ {connectionStatus === "connected" && serverImplementation && ( +
+
+ {(serverImplementation as WithIcons).icons && + (serverImplementation as WithIcons).icons!.length > 0 ? ( + + ) : ( + + )} + {(serverImplementation as { websiteUrl?: string }) + .websiteUrl ? ( + + {serverImplementation.name || "MCP Server"} + + ) : ( + + {serverImplementation.name || "MCP Server"} + + )} +
+ {serverImplementation.version && ( +
+ Version: {serverImplementation.version} +
+ )} +
+ )} + {loggingSupported && connectionStatus === "connected" && (