()
| 13 | } |
| 14 | |
| 15 | export function useMCPClient() { |
| 16 | const connectionsRef = useRef(new Map()) |
| 17 | const toolIndexRef = useRef(new Map()) |
| 18 | const [connectionStatuses, setConnectionStatuses] = useState({}) |
| 19 | |
| 20 | const updateStatus = useCallback((serverId, status, error = null) => { |
| 21 | setConnectionStatuses(prev => ({ ...prev, [serverId]: { status, error } })) |
| 22 | }, []) |
| 23 | |
| 24 | const connect = useCallback(async (serverConfig) => { |
| 25 | const { id, url, headers = {}, useProxy = true } = serverConfig |
| 26 | if (connectionsRef.current.has(id)) return |
| 27 | |
| 28 | updateStatus(id, 'connecting') |
| 29 | |
| 30 | const proxyUrl = buildProxyUrl(url, useProxy) |
| 31 | const transportHeaders = { ...headers } |
| 32 | |
| 33 | let client = null |
| 34 | let transport = null |
| 35 | |
| 36 | // Try StreamableHTTP first, then SSE fallback |
| 37 | for (const TransportClass of [StreamableHTTPClientTransport, SSEClientTransport]) { |
| 38 | try { |
| 39 | transport = new TransportClass(proxyUrl, { requestInit: { headers: transportHeaders } }) |
| 40 | client = new Client({ name: 'LocalAI-WebUI', version: '1.0.0' }) |
| 41 | await client.connect(transport) |
| 42 | break |
| 43 | } catch (err) { |
| 44 | client = null |
| 45 | transport = null |
| 46 | if (TransportClass === SSEClientTransport) { |
| 47 | updateStatus(id, 'error', err.message) |
| 48 | return |
| 49 | } |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | if (!client) { |
| 54 | updateStatus(id, 'error', 'Failed to connect with any transport') |
| 55 | return |
| 56 | } |
| 57 | |
| 58 | try { |
| 59 | const { tools = [] } = await client.listTools() |
| 60 | |
| 61 | // Remove old tool index entries for this server |
| 62 | for (const [toolName, sId] of toolIndexRef.current) { |
| 63 | if (sId === id) toolIndexRef.current.delete(toolName) |
| 64 | } |
| 65 | |
| 66 | for (const tool of tools) { |
| 67 | toolIndexRef.current.set(tool.name, id) |
| 68 | } |
| 69 | |
| 70 | connectionsRef.current.set(id, { client, transport, tools, serverConfig }) |
| 71 | updateStatus(id, 'connected') |
| 72 | } catch (err) { |
no test coverage detected