feat: add MCP prompts support to useMcp hook
- Add Prompt type from MCP SDK - Add prompts array to UseMcpResult - Fetch prompts automatically after resources during connection - Add listPrompts() method to manually refresh prompts list - Add getPrompt(name, args) method to get specific prompt messages - Clear prompts state on disconnect 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
8373adfdf9
commit
8377abf268
2 changed files with 73 additions and 3 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { Tool, Resource, ResourceTemplate } from '@modelcontextprotocol/sdk/types.js'
|
||||
import { Tool, Resource, ResourceTemplate, Prompt } from '@modelcontextprotocol/sdk/types.js'
|
||||
|
||||
export type UseMcpOptions = {
|
||||
/** The /sse URL of your remote MCP server */
|
||||
|
|
@ -39,6 +39,8 @@ export type UseMcpResult = {
|
|||
resources: Resource[]
|
||||
/** List of resource templates available from the connected MCP server */
|
||||
resourceTemplates: ResourceTemplate[]
|
||||
/** List of prompts available from the connected MCP server */
|
||||
prompts: Prompt[]
|
||||
/**
|
||||
* The current state of the MCP connection:
|
||||
* - 'discovering': Checking server existence and capabilities (including auth requirements).
|
||||
|
|
@ -80,6 +82,23 @@ export type UseMcpResult = {
|
|||
* @throws If the client is not in the 'ready' state or the read fails.
|
||||
*/
|
||||
readResource: (uri: string) => Promise<{ contents: Array<{ uri: string; mimeType?: string; text?: string; blob?: string }> }>
|
||||
/**
|
||||
* Function to list prompts from the MCP server.
|
||||
* @returns A promise that resolves when prompts are refreshed.
|
||||
* @throws If the client is not in the 'ready' state.
|
||||
*/
|
||||
listPrompts: () => Promise<void>
|
||||
/**
|
||||
* Function to get a specific prompt from the MCP server.
|
||||
* @param name The name of the prompt to get.
|
||||
* @param args Optional arguments for the prompt.
|
||||
* @returns A promise that resolves with the prompt messages.
|
||||
* @throws If the client is not in the 'ready' state or the get fails.
|
||||
*/
|
||||
getPrompt: (
|
||||
name: string,
|
||||
args?: Record<string, string>,
|
||||
) => Promise<{ messages: Array<{ role: 'user' | 'assistant'; content: { type: string; text?: string; [key: string]: any } }> }>
|
||||
/** Manually attempts to reconnect if the state is 'failed'. */
|
||||
retry: () => void
|
||||
/** Disconnects the client from the MCP server. */
|
||||
|
|
|
|||
|
|
@ -5,9 +5,12 @@ import {
|
|||
ListToolsResultSchema,
|
||||
ListResourcesResultSchema,
|
||||
ReadResourceResultSchema,
|
||||
ListPromptsResultSchema,
|
||||
GetPromptResultSchema,
|
||||
Tool,
|
||||
Resource,
|
||||
ResourceTemplate,
|
||||
Prompt,
|
||||
} from '@modelcontextprotocol/sdk/types.js'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
// Import both transport types
|
||||
|
|
@ -50,6 +53,7 @@ export function useMcp(options: UseMcpOptions): UseMcpResult {
|
|||
const [tools, setTools] = useState<Tool[]>([])
|
||||
const [resources, setResources] = useState<Resource[]>([])
|
||||
const [resourceTemplates, setResourceTemplates] = useState<ResourceTemplate[]>([])
|
||||
const [prompts, setPrompts] = useState<Prompt[]>([])
|
||||
const [error, setError] = useState<string | undefined>(undefined)
|
||||
const [log, setLog] = useState<UseMcpResult['log']>([])
|
||||
const [authUrl, setAuthUrl] = useState<string | undefined>(undefined)
|
||||
|
|
@ -108,6 +112,7 @@ export function useMcp(options: UseMcpOptions): UseMcpResult {
|
|||
setTools([])
|
||||
setResources([])
|
||||
setResourceTemplates([])
|
||||
setPrompts([])
|
||||
setError(undefined)
|
||||
setAuthUrl(undefined)
|
||||
}
|
||||
|
|
@ -296,7 +301,7 @@ export function useMcp(options: UseMcpOptions): UseMcpResult {
|
|||
await clientRef.current!.connect(transportInstance)
|
||||
|
||||
// --- Success Path ---
|
||||
addLog('info', `Client connected via ${transportType.toUpperCase()}. Loading tools and resources...`)
|
||||
addLog('info', `Client connected via ${transportType.toUpperCase()}. Loading tools, resources, and prompts...`)
|
||||
successfulTransportRef.current = transportType // Store successful type
|
||||
setState('loading')
|
||||
|
||||
|
|
@ -305,14 +310,18 @@ export function useMcp(options: UseMcpOptions): UseMcpResult {
|
|||
// Load resources after tools
|
||||
const resourcesResponse = await clientRef.current!.request({ method: 'resources/list' }, ListResourcesResultSchema)
|
||||
|
||||
// Load prompts after resources
|
||||
const promptsResponse = await clientRef.current!.request({ method: 'prompts/list' }, ListPromptsResultSchema)
|
||||
|
||||
if (isMountedRef.current) {
|
||||
// Check mount before final state updates
|
||||
setTools(toolsResponse.tools)
|
||||
setResources(resourcesResponse.resources)
|
||||
setResourceTemplates(Array.isArray(resourcesResponse.resourceTemplates) ? resourcesResponse.resourceTemplates : [])
|
||||
setPrompts(promptsResponse.prompts)
|
||||
addLog(
|
||||
'info',
|
||||
`Loaded ${toolsResponse.tools.length} tools, ${resourcesResponse.resources.length} resources, ${Array.isArray(resourcesResponse.resourceTemplates) ? resourcesResponse.resourceTemplates.length : 0} resource templates.`,
|
||||
`Loaded ${toolsResponse.tools.length} tools, ${resourcesResponse.resources.length} resources, ${Array.isArray(resourcesResponse.resourceTemplates) ? resourcesResponse.resourceTemplates.length : 0} resource templates, ${promptsResponse.prompts.length} prompts.`,
|
||||
)
|
||||
setState('ready') // Final success state
|
||||
// connectingRef will be set to false after orchestration logic
|
||||
|
|
@ -668,6 +677,45 @@ export function useMcp(options: UseMcpOptions): UseMcpResult {
|
|||
[state, addLog],
|
||||
) // Depends on state for error message and stable addLog
|
||||
|
||||
// listPrompts is stable (depends on stable addLog)
|
||||
const listPrompts = useCallback(async () => {
|
||||
// Use stateRef for check, state for throwing error message
|
||||
if (stateRef.current !== 'ready' || !clientRef.current) {
|
||||
throw new Error(`MCP client is not ready (current state: ${state}). Cannot list prompts.`)
|
||||
}
|
||||
addLog('info', 'Listing prompts...')
|
||||
try {
|
||||
const promptsResponse = await clientRef.current.request({ method: 'prompts/list' }, ListPromptsResultSchema)
|
||||
if (isMountedRef.current) {
|
||||
setPrompts(promptsResponse.prompts)
|
||||
addLog('info', `Listed ${promptsResponse.prompts.length} prompts.`)
|
||||
}
|
||||
} catch (err) {
|
||||
addLog('error', `Error listing prompts: ${err instanceof Error ? err.message : String(err)}`, err)
|
||||
throw err
|
||||
}
|
||||
}, [state, addLog]) // Depends on state for error message and stable addLog
|
||||
|
||||
// getPrompt is stable (depends on stable addLog)
|
||||
const getPrompt = useCallback(
|
||||
async (name: string, args?: Record<string, string>) => {
|
||||
// Use stateRef for check, state for throwing error message
|
||||
if (stateRef.current !== 'ready' || !clientRef.current) {
|
||||
throw new Error(`MCP client is not ready (current state: ${state}). Cannot get prompt "${name}".`)
|
||||
}
|
||||
addLog('info', `Getting prompt: ${name}`, args)
|
||||
try {
|
||||
const result = await clientRef.current.request({ method: 'prompts/get', params: { name, arguments: args } }, GetPromptResultSchema)
|
||||
addLog('info', `Prompt "${name}" retrieved successfully`)
|
||||
return result
|
||||
} catch (err) {
|
||||
addLog('error', `Error getting prompt "${name}": ${err instanceof Error ? err.message : String(err)}`, err)
|
||||
throw err
|
||||
}
|
||||
},
|
||||
[state, addLog],
|
||||
) // Depends on state for error message and stable addLog
|
||||
|
||||
// ===== Effects =====
|
||||
|
||||
// Effect for handling auth callback messages from popup (Stable dependencies)
|
||||
|
|
@ -757,12 +805,15 @@ export function useMcp(options: UseMcpOptions): UseMcpResult {
|
|||
tools,
|
||||
resources,
|
||||
resourceTemplates,
|
||||
prompts,
|
||||
error,
|
||||
log,
|
||||
authUrl,
|
||||
callTool,
|
||||
listResources,
|
||||
readResource,
|
||||
listPrompts,
|
||||
getPrompt,
|
||||
retry,
|
||||
disconnect,
|
||||
authenticate,
|
||||
|
|
|
|||
Loading…
Reference in a new issue