From 7a923c350956f928af4110857944145ccc63540b Mon Sep 17 00:00:00 2001 From: Jem <591643+jem-computer@users.noreply.github.com> Date: Thu, 19 Jun 2025 18:46:06 -0700 Subject: [PATCH] feat(examples): add resources and prompts display to inspector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Import and export Resource, ResourceTemplate, and Prompt types - Add state management for resources and prompts in McpServers component - Add UI sections to display available resources and prompts - Implement readResource functionality with content display - Implement getPrompt functionality with argument inputs - Show resource templates with visual distinction - Add expand/collapse UI for resources and prompts - Display prompt messages with proper formatting 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../inspector/src/components/McpServers.tsx | 273 +++++++++++++++++- src/react/index.ts | 4 +- 2 files changed, 269 insertions(+), 8 deletions(-) diff --git a/examples/inspector/src/components/McpServers.tsx b/examples/inspector/src/components/McpServers.tsx index b99160d..95b52fc 100644 --- a/examples/inspector/src/components/McpServers.tsx +++ b/examples/inspector/src/components/McpServers.tsx @@ -1,6 +1,6 @@ import { useState, useRef, useEffect } from 'react' -import { useMcp, type Tool } from 'use-mcp/react' -import { Info, X, ChevronRight, ChevronDown } from 'lucide-react' +import { useMcp, type Tool, type Resource, type ResourceTemplate, type Prompt } from 'use-mcp/react' +import { Info, X, ChevronRight, ChevronDown, FileText, MessageSquare } from 'lucide-react' // MCP Connection wrapper that only renders when active function McpConnection({ @@ -24,7 +24,16 @@ function McpConnection({ // Update parent component with connection data useEffect(() => { onConnectionUpdate(connection) - }, [connection.state, connection.tools, connection.error, connection.log.length, connection.authUrl]) + }, [ + connection.state, + connection.tools, + connection.resources, + connection.resourceTemplates, + connection.prompts, + connection.error, + connection.log.length, + connection.authUrl, + ]) // Return null as this is just a hook wrapper return null @@ -42,23 +51,38 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[]) const [connectionData, setConnectionData] = useState({ state: 'not-connected', tools: [], + resources: [], + resourceTemplates: [], + prompts: [], error: undefined, log: [], authUrl: undefined, retry: () => {}, disconnect: () => {}, authenticate: () => Promise.resolve(undefined), - callTool: (_name: string, _args?: Record) => Promise.resolve(undefined), + callTool: (_name: string, _args?: Record) => + Promise.resolve(undefined), + listResources: () => Promise.resolve(), + readResource: (_uri: string) => Promise.resolve({ contents: [] }), + listPrompts: () => Promise.resolve(), + getPrompt: (_name: string, _args?: Record) => + Promise.resolve({ messages: [] }), clearStorage: () => {}, }) const [toolForms, setToolForms] = useState>>({}) const [toolExecutionLogs, setToolExecutionLogs] = useState>({}) const [expandedTools, setExpandedTools] = useState>({}) + const [expandedResources, setExpandedResources] = useState>({}) + const [expandedPrompts, setExpandedPrompts] = useState>({}) + const [resourceContents, setResourceContents] = useState>({}) + const [promptResults, setPromptResults] = useState>({}) + const [promptArgs, setPromptArgs] = useState>>({}) const logRef = useRef(null) const executionLogRefs = useRef>({}) // Extract connection properties - const { state, tools, log, authUrl, disconnect, authenticate } = connectionData + const { state, tools, resources, resourceTemplates, prompts, log, authUrl, disconnect, authenticate, readResource, getPrompt } = + connectionData // Notify parent component when tools change useEffect(() => { @@ -85,13 +109,22 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[]) setConnectionData({ state: 'not-connected', tools: [], + resources: [], + resourceTemplates: [], + prompts: [], error: undefined, log: [], authUrl: undefined, retry: () => {}, disconnect: () => {}, authenticate: () => Promise.resolve(undefined), - callTool: (_name: string, _args?: Record) => Promise.resolve(undefined), + callTool: (_name: string, _args?: Record) => + Promise.resolve(undefined), + listResources: () => Promise.resolve(), + readResource: (_uri: string) => Promise.resolve({ contents: [] }), + listPrompts: () => Promise.resolve(), + getPrompt: (_name: string, _args?: Record) => + Promise.resolve({ messages: [] }), clearStorage: () => {}, }) } @@ -460,6 +493,234 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[]) )} + {/* Available Resources section */} +
+

+ Available Resources ({resources.length + resourceTemplates.length}) +

+ + {resources.length === 0 && resourceTemplates.length === 0 ? ( +
+ No resources available. Connect to an MCP server to see available resources. +
+ ) : ( +
+ {/* Direct Resources */} + {resources.map((resource: Resource, index: number) => { + const isExpanded = expandedResources[resource.uri] || false + const contents = resourceContents[resource.uri] + + return ( +
+
+
+ +
+
+ +

{resource.name}

+
+ {resource.description && ( +

{resource.description}

+ )} +

{resource.uri}

+ {resource.mimeType && ( + ({resource.mimeType}) + )} +
+
+ + {isExpanded && ( +
+ + + {contents && ( +
+ {contents.error ? ( +
+ Error: {contents.error} +
+ ) : ( +
+ {contents.contents?.map((content: any, idx: number) => ( +
+
+ {content.uri} {content.mimeType && `(${content.mimeType})`} +
+
+                                        {content.text || (content.blob && '[Binary content]') || '[No content]'}
+                                      
+
+ ))} +
+ )} +
+ )} +
+ )} +
+
+ ) + })} + + {/* Resource Templates */} + {resourceTemplates.map((template: ResourceTemplate, index: number) => ( +
+
+
+ +

{template.name}

+ Template +
+ {template.description && ( +

{template.description}

+ )} +

{template.uriTemplate}

+ {template.mimeType && ( + ({template.mimeType}) + )} +
+
+ ))} +
+ )} +
+ + {/* Available Prompts section */} +
+

+ Available Prompts ({prompts.length}) +

+ + {prompts.length === 0 ? ( +
+ No prompts available. Connect to an MCP server to see available prompts. +
+ ) : ( +
+ {prompts.map((prompt: Prompt, index: number) => { + const isExpanded = expandedPrompts[prompt.name] || false + const result = promptResults[prompt.name] + const args = promptArgs[prompt.name] || {} + + return ( +
+
+
+ +
+
+ +

{prompt.name}

+
+ {prompt.description && ( +

{prompt.description}

+ )} +
+
+ + {isExpanded && ( +
+ {/* Prompt Arguments */} + {prompt.arguments && prompt.arguments.length > 0 && ( +
+
Arguments:
+ {prompt.arguments.map((arg: any) => ( +
+ + setPromptArgs(prev => ({ + ...prev, + [prompt.name]: { + ...prev[prompt.name], + [arg.name]: e.target.value + } + }))} + placeholder={arg.description || `Enter ${arg.name}`} + /> +
+ ))} +
+ )} + + + + {result && ( +
+ {result.error ? ( +
+ Error: {result.error} +
+ ) : ( +
+
Messages:
+ {result.messages?.map((message: any, idx: number) => ( +
+
+ {message.role}: +
+
+                                        {message.content.text || JSON.stringify(message.content, null, 2)}
+                                      
+
+ ))} +
+ )} +
+ )} +
+ )} +
+
+ ) + })} +
+ )} +
+ {/* Debug Log */}
diff --git a/src/react/index.ts b/src/react/index.ts index c2aedd7..25c9f76 100644 --- a/src/react/index.ts +++ b/src/react/index.ts @@ -6,5 +6,5 @@ export { useMcp } from './useMcp.js' export type { UseMcpOptions, UseMcpResult } from './types.js' -// Re-export core Tool type for convenience when using hook result? -export type { Tool } from '@modelcontextprotocol/sdk/types.js' +// Re-export core types for convenience when using hook result +export type { Tool, Resource, ResourceTemplate, Prompt } from '@modelcontextprotocol/sdk/types.js'