docs: update README files with resources and prompts documentation
- Add resources, resourceTemplates, and prompts to all feature lists - Document new properties returned by useMcp hook - Document new methods: listResources, readResource, listPrompts, getPrompt - Add code examples showing how to use resources and prompts - Update quick start examples to demonstrate all features - Add note about graceful handling of servers with partial MCP support 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
d4220ec5f2
commit
b909730ae2
4 changed files with 153 additions and 63 deletions
40
README.md
40
README.md
|
|
@ -25,6 +25,9 @@ yarn add use-mcp
|
||||||
- 🔄 Automatic connection management with reconnection and retries
|
- 🔄 Automatic connection management with reconnection and retries
|
||||||
- 🔐 OAuth authentication flow handling with popup and fallback support
|
- 🔐 OAuth authentication flow handling with popup and fallback support
|
||||||
- 📦 Simple React hook interface for MCP integration
|
- 📦 Simple React hook interface for MCP integration
|
||||||
|
- 🧰 Full support for MCP tools, resources, and prompts
|
||||||
|
- 📄 Access server resources and read their contents
|
||||||
|
- 💬 Use server-provided prompt templates
|
||||||
- 🧰 TypeScript types for editor assistance and type checking
|
- 🧰 TypeScript types for editor assistance and type checking
|
||||||
- 📝 Comprehensive logging for debugging
|
- 📝 Comprehensive logging for debugging
|
||||||
- 🌐 Works with both HTTP and SSE (Server-Sent Events) transports
|
- 🌐 Works with both HTTP and SSE (Server-Sent Events) transports
|
||||||
|
|
@ -38,8 +41,12 @@ function MyAIComponent() {
|
||||||
const {
|
const {
|
||||||
state, // Connection state: 'discovering' | 'pending_auth' | 'authenticating' | 'connecting' | 'loading' | 'ready' | 'failed'
|
state, // Connection state: 'discovering' | 'pending_auth' | 'authenticating' | 'connecting' | 'loading' | 'ready' | 'failed'
|
||||||
tools, // Available tools from MCP server
|
tools, // Available tools from MCP server
|
||||||
|
resources, // Available resources from MCP server
|
||||||
|
prompts, // Available prompts from MCP server
|
||||||
error, // Error message if connection failed
|
error, // Error message if connection failed
|
||||||
callTool, // Function to call tools on the MCP server
|
callTool, // Function to call tools on the MCP server
|
||||||
|
readResource, // Function to read resource contents
|
||||||
|
getPrompt, // Function to get prompt messages
|
||||||
retry, // Retry connection manually
|
retry, // Retry connection manually
|
||||||
authenticate, // Manually trigger authentication
|
authenticate, // Manually trigger authentication
|
||||||
clearStorage, // Clear stored tokens and credentials
|
clearStorage, // Clear stored tokens and credentials
|
||||||
|
|
@ -83,6 +90,32 @@ function MyAIComponent() {
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
<button onClick={handleSearch}>Search</button>
|
<button onClick={handleSearch}>Search</button>
|
||||||
|
|
||||||
|
{/* Example: Display and read resources */}
|
||||||
|
{resources.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<h3>Resources: {resources.length}</h3>
|
||||||
|
<button onClick={async () => {
|
||||||
|
const content = await readResource(resources[0].uri)
|
||||||
|
console.log('Resource content:', content)
|
||||||
|
}}>
|
||||||
|
Read First Resource
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Example: Use prompts */}
|
||||||
|
{prompts.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<h3>Prompts: {prompts.length}</h3>
|
||||||
|
<button onClick={async () => {
|
||||||
|
const result = await getPrompt(prompts[0].name)
|
||||||
|
console.log('Prompt messages:', result.messages)
|
||||||
|
}}>
|
||||||
|
Get First Prompt
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -176,10 +209,17 @@ function useMcp(options: UseMcpOptions): UseMcpResult
|
||||||
|----------|------|-------------|
|
|----------|------|-------------|
|
||||||
| `state` | `string` | Current connection state: 'discovering', 'pending_auth', 'authenticating', 'connecting', 'loading', 'ready', 'failed' |
|
| `state` | `string` | Current connection state: 'discovering', 'pending_auth', 'authenticating', 'connecting', 'loading', 'ready', 'failed' |
|
||||||
| `tools` | `Tool[]` | Available tools from the MCP server |
|
| `tools` | `Tool[]` | Available tools from the MCP server |
|
||||||
|
| `resources` | `Resource[]` | Available resources from the MCP server |
|
||||||
|
| `resourceTemplates` | `ResourceTemplate[]` | Available resource templates from the MCP server |
|
||||||
|
| `prompts` | `Prompt[]` | Available prompts from the MCP server |
|
||||||
| `error` | `string \| undefined` | Error message if connection failed |
|
| `error` | `string \| undefined` | Error message if connection failed |
|
||||||
| `authUrl` | `string \| undefined` | Manual authentication URL if popup is blocked |
|
| `authUrl` | `string \| undefined` | Manual authentication URL if popup is blocked |
|
||||||
| `log` | `{ level: 'debug' \| 'info' \| 'warn' \| 'error'; message: string; timestamp: number }[]` | Array of log messages |
|
| `log` | `{ level: 'debug' \| 'info' \| 'warn' \| 'error'; message: string; timestamp: number }[]` | Array of log messages |
|
||||||
| `callTool` | `(name: string, args?: Record<string, unknown>) => Promise<any>` | Function to call a tool on the MCP server |
|
| `callTool` | `(name: string, args?: Record<string, unknown>) => Promise<any>` | Function to call a tool on the MCP server |
|
||||||
|
| `listResources` | `() => Promise<void>` | Refresh the list of available resources |
|
||||||
|
| `readResource` | `(uri: string) => Promise<{ contents: Array<...> }>` | Read the contents of a specific resource |
|
||||||
|
| `listPrompts` | `() => Promise<void>` | Refresh the list of available prompts |
|
||||||
|
| `getPrompt` | `(name: string, args?: Record<string, string>) => Promise<{ messages: Array<...> }>` | Get a specific prompt with optional arguments |
|
||||||
| `retry` | `() => void` | Manually attempt to reconnect |
|
| `retry` | `() => void` | Manually attempt to reconnect |
|
||||||
| `disconnect` | `() => void` | Disconnect from the MCP server |
|
| `disconnect` | `() => void` | Disconnect from the MCP server |
|
||||||
| `authenticate` | `() => void` | Manually trigger authentication |
|
| `authenticate` | `() => void` | Manually trigger authentication |
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ A minimal demo showcasing the `use-mcp` React hook for connecting to Model Conte
|
||||||
|
|
||||||
- Connect to any MCP server via URL
|
- Connect to any MCP server via URL
|
||||||
- View available tools and their schemas
|
- View available tools and their schemas
|
||||||
|
- Browse and read server resources
|
||||||
|
- Interact with server-provided prompts
|
||||||
- Real-time connection status monitoring
|
- Real-time connection status monitoring
|
||||||
- Debug logging for troubleshooting
|
- Debug logging for troubleshooting
|
||||||
- Clean, minimal UI focused on MCP functionality
|
- Clean, minimal UI focused on MCP functionality
|
||||||
|
|
@ -31,7 +33,7 @@ pnpm dev
|
||||||
|
|
||||||
3. Open your browser and navigate to the displayed local URL
|
3. Open your browser and navigate to the displayed local URL
|
||||||
|
|
||||||
4. Enter an MCP server URL to test the connection and explore available tools
|
4. Enter an MCP server URL to test the connection and explore available tools, resources, and prompts
|
||||||
|
|
||||||
## What This Demonstrates
|
## What This Demonstrates
|
||||||
|
|
||||||
|
|
@ -46,7 +48,17 @@ const connection = useMcp({
|
||||||
autoRetry: false
|
autoRetry: false
|
||||||
})
|
})
|
||||||
|
|
||||||
// Access connection.state, connection.tools, connection.error, etc.
|
// Access connection.state, connection.tools, connection.resources,
|
||||||
|
// connection.prompts, connection.error, etc.
|
||||||
```
|
```
|
||||||
|
|
||||||
The `McpServers` component wraps this hook to provide a complete UI for server management and tool inspection.
|
The `McpServers` component wraps this hook to provide a complete UI for server management, tool inspection, resource browsing, and prompt interaction.
|
||||||
|
|
||||||
|
## Supported MCP Features
|
||||||
|
|
||||||
|
- **Tools**: Execute server-provided tools with custom arguments and view results
|
||||||
|
- **Resources**: Browse available resources and read their contents (text or binary)
|
||||||
|
- **Resource Templates**: View dynamic resource templates with URI patterns
|
||||||
|
- **Prompts**: Interact with server prompts, provide arguments, and view generated messages
|
||||||
|
|
||||||
|
Note: Not all MCP servers implement all features. The inspector will gracefully handle servers that only support a subset of the MCP specification.
|
||||||
|
|
|
||||||
|
|
@ -60,13 +60,11 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
retry: () => {},
|
retry: () => {},
|
||||||
disconnect: () => {},
|
disconnect: () => {},
|
||||||
authenticate: () => Promise.resolve(undefined),
|
authenticate: () => Promise.resolve(undefined),
|
||||||
callTool: (_name: string, _args?: Record<string, unknown>) =>
|
callTool: (_name: string, _args?: Record<string, unknown>) => Promise.resolve(undefined),
|
||||||
Promise.resolve(undefined),
|
|
||||||
listResources: () => Promise.resolve(),
|
listResources: () => Promise.resolve(),
|
||||||
readResource: (_uri: string) => Promise.resolve({ contents: [] }),
|
readResource: (_uri: string) => Promise.resolve({ contents: [] }),
|
||||||
listPrompts: () => Promise.resolve(),
|
listPrompts: () => Promise.resolve(),
|
||||||
getPrompt: (_name: string, _args?: Record<string, string>) =>
|
getPrompt: (_name: string, _args?: Record<string, string>) => Promise.resolve({ messages: [] }),
|
||||||
Promise.resolve({ messages: [] }),
|
|
||||||
clearStorage: () => {},
|
clearStorage: () => {},
|
||||||
})
|
})
|
||||||
const [toolForms, setToolForms] = useState<Record<string, Record<string, any>>>({})
|
const [toolForms, setToolForms] = useState<Record<string, Record<string, any>>>({})
|
||||||
|
|
@ -118,13 +116,11 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
retry: () => {},
|
retry: () => {},
|
||||||
disconnect: () => {},
|
disconnect: () => {},
|
||||||
authenticate: () => Promise.resolve(undefined),
|
authenticate: () => Promise.resolve(undefined),
|
||||||
callTool: (_name: string, _args?: Record<string, unknown>) =>
|
callTool: (_name: string, _args?: Record<string, unknown>) => Promise.resolve(undefined),
|
||||||
Promise.resolve(undefined),
|
|
||||||
listResources: () => Promise.resolve(),
|
listResources: () => Promise.resolve(),
|
||||||
readResource: (_uri: string) => Promise.resolve({ contents: [] }),
|
readResource: (_uri: string) => Promise.resolve({ contents: [] }),
|
||||||
listPrompts: () => Promise.resolve(),
|
listPrompts: () => Promise.resolve(),
|
||||||
getPrompt: (_name: string, _args?: Record<string, string>) =>
|
getPrompt: (_name: string, _args?: Record<string, string>) => Promise.resolve({ messages: [] }),
|
||||||
Promise.resolve({ messages: [] }),
|
|
||||||
clearStorage: () => {},
|
clearStorage: () => {},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -495,9 +491,7 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
|
|
||||||
{/* Available Resources section */}
|
{/* Available Resources section */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-medium text-sm mb-3">
|
<h3 className="font-medium text-sm mb-3">Available Resources ({resources.length + resourceTemplates.length})</h3>
|
||||||
Available Resources ({resources.length + resourceTemplates.length})
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
{resources.length === 0 && resourceTemplates.length === 0 ? (
|
{resources.length === 0 && resourceTemplates.length === 0 ? (
|
||||||
<div className="border border-gray-200 rounded p-4 bg-gray-50 text-center text-gray-500 text-sm">
|
<div className="border border-gray-200 rounded p-4 bg-gray-50 text-center text-gray-500 text-sm">
|
||||||
|
|
@ -515,7 +509,7 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
<div className="p-3">
|
<div className="p-3">
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<button
|
<button
|
||||||
onClick={() => setExpandedResources(prev => ({ ...prev, [resource.uri]: !isExpanded }))}
|
onClick={() => setExpandedResources((prev) => ({ ...prev, [resource.uri]: !isExpanded }))}
|
||||||
className="text-gray-500 hover:text-gray-700 mt-0.5"
|
className="text-gray-500 hover:text-gray-700 mt-0.5"
|
||||||
>
|
>
|
||||||
{isExpanded ? <ChevronDown size={16} /> : <ChevronRight size={16} />}
|
{isExpanded ? <ChevronDown size={16} /> : <ChevronRight size={16} />}
|
||||||
|
|
@ -525,13 +519,9 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
<FileText size={14} className="text-gray-400" />
|
<FileText size={14} className="text-gray-400" />
|
||||||
<h4 className="font-medium text-sm">{resource.name}</h4>
|
<h4 className="font-medium text-sm">{resource.name}</h4>
|
||||||
</div>
|
</div>
|
||||||
{resource.description && (
|
{resource.description && <p className="text-xs text-gray-500 mt-1">{resource.description}</p>}
|
||||||
<p className="text-xs text-gray-500 mt-1">{resource.description}</p>
|
|
||||||
)}
|
|
||||||
<p className="text-xs text-gray-400 mt-1 font-mono">{resource.uri}</p>
|
<p className="text-xs text-gray-400 mt-1 font-mono">{resource.uri}</p>
|
||||||
{resource.mimeType && (
|
{resource.mimeType && <span className="text-xs text-gray-400">({resource.mimeType})</span>}
|
||||||
<span className="text-xs text-gray-400">({resource.mimeType})</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -541,9 +531,9 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
try {
|
try {
|
||||||
const result = await readResource(resource.uri)
|
const result = await readResource(resource.uri)
|
||||||
setResourceContents(prev => ({ ...prev, [resource.uri]: result }))
|
setResourceContents((prev) => ({ ...prev, [resource.uri]: result }))
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
setResourceContents(prev => ({ ...prev, [resource.uri]: { error: error.message } }))
|
setResourceContents((prev) => ({ ...prev, [resource.uri]: { error: error.message } }))
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="px-3 py-1 bg-blue-600 hover:bg-blue-700 text-white rounded text-xs font-medium"
|
className="px-3 py-1 bg-blue-600 hover:bg-blue-700 text-white rounded text-xs font-medium"
|
||||||
|
|
@ -589,13 +579,9 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
<h4 className="font-medium text-sm">{template.name}</h4>
|
<h4 className="font-medium text-sm">{template.name}</h4>
|
||||||
<span className="text-xs text-blue-600 bg-blue-50 px-2 py-0.5 rounded">Template</span>
|
<span className="text-xs text-blue-600 bg-blue-50 px-2 py-0.5 rounded">Template</span>
|
||||||
</div>
|
</div>
|
||||||
{template.description && (
|
{template.description && <p className="text-xs text-gray-500 mt-1">{template.description}</p>}
|
||||||
<p className="text-xs text-gray-500 mt-1">{template.description}</p>
|
|
||||||
)}
|
|
||||||
<p className="text-xs text-gray-400 mt-1 font-mono">{template.uriTemplate}</p>
|
<p className="text-xs text-gray-400 mt-1 font-mono">{template.uriTemplate}</p>
|
||||||
{template.mimeType && (
|
{template.mimeType && <span className="text-xs text-gray-400">({template.mimeType})</span>}
|
||||||
<span className="text-xs text-gray-400">({template.mimeType})</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
@ -605,9 +591,7 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
|
|
||||||
{/* Available Prompts section */}
|
{/* Available Prompts section */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-medium text-sm mb-3">
|
<h3 className="font-medium text-sm mb-3">Available Prompts ({prompts.length})</h3>
|
||||||
Available Prompts ({prompts.length})
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
{prompts.length === 0 ? (
|
{prompts.length === 0 ? (
|
||||||
<div className="border border-gray-200 rounded p-4 bg-gray-50 text-center text-gray-500 text-sm">
|
<div className="border border-gray-200 rounded p-4 bg-gray-50 text-center text-gray-500 text-sm">
|
||||||
|
|
@ -625,7 +609,7 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
<div className="p-3">
|
<div className="p-3">
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<button
|
<button
|
||||||
onClick={() => setExpandedPrompts(prev => ({ ...prev, [prompt.name]: !isExpanded }))}
|
onClick={() => setExpandedPrompts((prev) => ({ ...prev, [prompt.name]: !isExpanded }))}
|
||||||
className="text-gray-500 hover:text-gray-700 mt-0.5"
|
className="text-gray-500 hover:text-gray-700 mt-0.5"
|
||||||
>
|
>
|
||||||
{isExpanded ? <ChevronDown size={16} /> : <ChevronRight size={16} />}
|
{isExpanded ? <ChevronDown size={16} /> : <ChevronRight size={16} />}
|
||||||
|
|
@ -635,9 +619,7 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
<MessageSquare size={14} className="text-purple-400" />
|
<MessageSquare size={14} className="text-purple-400" />
|
||||||
<h4 className="font-medium text-sm">{prompt.name}</h4>
|
<h4 className="font-medium text-sm">{prompt.name}</h4>
|
||||||
</div>
|
</div>
|
||||||
{prompt.description && (
|
{prompt.description && <p className="text-xs text-gray-500 mt-1">{prompt.description}</p>}
|
||||||
<p className="text-xs text-gray-500 mt-1">{prompt.description}</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -652,21 +634,21 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
<label className="text-xs text-gray-600">
|
<label className="text-xs text-gray-600">
|
||||||
{arg.name}
|
{arg.name}
|
||||||
{arg.required && <span className="text-red-500 ml-1">*</span>}
|
{arg.required && <span className="text-red-500 ml-1">*</span>}
|
||||||
{arg.description && (
|
{arg.description && <span className="text-gray-400 ml-1">({arg.description})</span>}
|
||||||
<span className="text-gray-400 ml-1">({arg.description})</span>
|
|
||||||
)}
|
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="w-full p-2 border border-gray-200 rounded text-sm"
|
className="w-full p-2 border border-gray-200 rounded text-sm"
|
||||||
value={args[arg.name] || ''}
|
value={args[arg.name] || ''}
|
||||||
onChange={(e) => setPromptArgs(prev => ({
|
onChange={(e) =>
|
||||||
...prev,
|
setPromptArgs((prev) => ({
|
||||||
[prompt.name]: {
|
...prev,
|
||||||
...prev[prompt.name],
|
[prompt.name]: {
|
||||||
[arg.name]: e.target.value
|
...prev[prompt.name],
|
||||||
}
|
[arg.name]: e.target.value,
|
||||||
}))}
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
placeholder={arg.description || `Enter ${arg.name}`}
|
placeholder={arg.description || `Enter ${arg.name}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -678,9 +660,9 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
try {
|
try {
|
||||||
const result = await getPrompt(prompt.name, args)
|
const result = await getPrompt(prompt.name, args)
|
||||||
setPromptResults(prev => ({ ...prev, [prompt.name]: result }))
|
setPromptResults((prev) => ({ ...prev, [prompt.name]: result }))
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
setPromptResults(prev => ({ ...prev, [prompt.name]: { error: error.message } }))
|
setPromptResults((prev) => ({ ...prev, [prompt.name]: { error: error.message } }))
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="px-3 py-1 bg-purple-600 hover:bg-purple-700 text-white rounded text-xs font-medium"
|
className="px-3 py-1 bg-purple-600 hover:bg-purple-700 text-white rounded text-xs font-medium"
|
||||||
|
|
@ -699,9 +681,7 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
|
||||||
<h5 className="text-xs font-medium text-gray-700">Messages:</h5>
|
<h5 className="text-xs font-medium text-gray-700">Messages:</h5>
|
||||||
{result.messages?.map((message: any, idx: number) => (
|
{result.messages?.map((message: any, idx: number) => (
|
||||||
<div key={idx} className="border border-gray-200 rounded p-2">
|
<div key={idx} className="border border-gray-200 rounded p-2">
|
||||||
<div className="text-xs font-medium text-gray-700 mb-1">
|
<div className="text-xs font-medium text-gray-700 mb-1">{message.role}:</div>
|
||||||
{message.role}:
|
|
||||||
</div>
|
|
||||||
<pre className="text-xs font-mono bg-gray-50 p-2 rounded overflow-x-auto">
|
<pre className="text-xs font-mono bg-gray-50 p-2 rounded overflow-x-auto">
|
||||||
{message.content.text || JSON.stringify(message.content, null, 2)}
|
{message.content.text || JSON.stringify(message.content, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ The useMcp hook manages the connection to an MCP server, handles authentication
|
||||||
```tsx
|
```tsx
|
||||||
import { useMcp } from 'use-mcp'
|
import { useMcp } from 'use-mcp'
|
||||||
// Optional: Import types if needed
|
// Optional: Import types if needed
|
||||||
import type { UseMcpOptions, UseMcpResult, Tool } from 'use-mcp'
|
import type { UseMcpOptions, UseMcpResult, Tool, Resource, ResourceTemplate, Prompt } from 'use-mcp'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
@ -101,7 +101,12 @@ function MyChatComponent() {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{mcp.state === 'authenticating' && <p>Waiting for authentication...</p>}
|
{mcp.state === 'authenticating' && <p>Waiting for authentication...</p>}
|
||||||
{mcp.state === 'ready' && <p>Connected! Tools available: {mcp.tools.length}</p>}
|
{mcp.state === 'ready' && (
|
||||||
|
<p>
|
||||||
|
Connected! Tools: {mcp.tools.length}, Resources: {mcp.resources.length + mcp.resourceTemplates.length},
|
||||||
|
Prompts: {mcp.prompts.length}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Your Chat UI */}
|
{/* Your Chat UI */}
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -140,6 +145,52 @@ function MyChatComponent() {
|
||||||
<button onClick={mcp.clearStorage} style={{ marginTop: '10px' }}>
|
<button onClick={mcp.clearStorage} style={{ marginTop: '10px' }}>
|
||||||
Clear Stored Auth
|
Clear Stored Auth
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{/* Example: Working with Resources */}
|
||||||
|
{mcp.state === 'ready' && mcp.resources.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<h3>Available Resources:</h3>
|
||||||
|
{mcp.resources.map((resource) => (
|
||||||
|
<div key={resource.uri}>
|
||||||
|
<span>{resource.name}</span>
|
||||||
|
<button onClick={async () => {
|
||||||
|
try {
|
||||||
|
const content = await mcp.readResource(resource.uri)
|
||||||
|
console.log('Resource content:', content)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to read resource:', error)
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
Read
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Example: Working with Prompts */}
|
||||||
|
{mcp.state === 'ready' && mcp.prompts.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<h3>Available Prompts:</h3>
|
||||||
|
{mcp.prompts.map((prompt) => (
|
||||||
|
<div key={prompt.name}>
|
||||||
|
<span>{prompt.name}</span>
|
||||||
|
<button onClick={async () => {
|
||||||
|
try {
|
||||||
|
const result = await mcp.getPrompt(prompt.name, {
|
||||||
|
// Add any required arguments here
|
||||||
|
})
|
||||||
|
console.log('Prompt result:', result)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to get prompt:', error)
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
Get Prompt
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -163,11 +214,18 @@ export default MyChatComponent
|
||||||
### Hook Return Value (UseMcpResult)
|
### Hook Return Value (UseMcpResult)
|
||||||
|
|
||||||
- tools: An array of Tool objects provided by the server. Empty until state is 'ready'.
|
- tools: An array of Tool objects provided by the server. Empty until state is 'ready'.
|
||||||
|
- resources: An array of Resource objects representing data available from the server.
|
||||||
|
- resourceTemplates: An array of ResourceTemplate objects representing dynamic resources available from the server.
|
||||||
|
- prompts: An array of Prompt objects representing reusable prompt templates from the server.
|
||||||
- state: The current connection state ('discovering', 'authenticating', 'connecting', 'loading', 'ready', 'failed'). Use this to conditionally render UI or enable/disable features.
|
- state: The current connection state ('discovering', 'authenticating', 'connecting', 'loading', 'ready', 'failed'). Use this to conditionally render UI or enable/disable features.
|
||||||
- error: An error message if state is 'failed'.
|
- error: An error message if state is 'failed'.
|
||||||
- authUrl: If authentication is required and the popup was potentially blocked, this URL string can be used to let the user manually open the auth page (e.g., <a href={authUrl} target="_blank">...</a>).
|
- authUrl: If authentication is required and the popup was potentially blocked, this URL string can be used to let the user manually open the auth page (e.g., <a href={authUrl} target="_blank">...</a>).
|
||||||
- log: An array of log messages { level, message, timestamp }. Useful for debugging when debug option is true.
|
- log: An array of log messages { level, message, timestamp }. Useful for debugging when debug option is true.
|
||||||
- callTool(name, args): An async function to execute a tool on the MCP server. Throws an error if the client isn't ready or the call fails.
|
- callTool(name, args): An async function to execute a tool on the MCP server. Throws an error if the client isn't ready or the call fails.
|
||||||
|
- listResources(): An async function to refresh the list of available resources. Returns void.
|
||||||
|
- readResource(uri): An async function to read the contents of a specific resource. Returns an object with a 'contents' array containing the resource data.
|
||||||
|
- listPrompts(): An async function to refresh the list of available prompts. Returns void.
|
||||||
|
- getPrompt(name, args): An async function to get a specific prompt with optional arguments. Returns an object with a 'messages' array containing the prompt messages.
|
||||||
- retry(): Manually triggers a reconnection attempt if the state is 'failed'.
|
- retry(): Manually triggers a reconnection attempt if the state is 'failed'.
|
||||||
- disconnect(): Disconnects the client from the server.
|
- disconnect(): Disconnects the client from the server.
|
||||||
- authenticate(): Manually attempts to start the authentication flow. Useful for triggering the popup via a user click if it was initially blocked.
|
- authenticate(): Manually attempts to start the authentication flow. Useful for triggering the popup via a user click if it was initially blocked.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue