UNPKG

capacitor-cors-bypass-enhanced

Version:

Enhanced Capacitor plugin for CORS bypass with HTTP/2, HTTP/3, gRPC, GraphQL, file operations, and advanced networking features. Modular TypeScript definitions for better maintainability.

193 lines (192 loc) 6.29 kB
/** * MCP Client Manager (Web Implementation) * Manages MCP connections with StreamableHTTP transport */ import { StreamableHTTPTransport } from './streamable-http'; export class MCPClientManager { constructor() { this.connections = new Map(); this.connectionCounter = 0; } /** * Create a new MCP client connection */ async createClient(options) { this.connectionCounter++; const connectionId = `mcp_web_${this.connectionCounter}`; // Determine transport type const transport = options.transport || 'streamablehttp'; // Get endpoint URL let url = options.url; if (!url && options.sseUrl) { // Backward compatibility url = options.sseUrl; } if (!url) { throw new Error('URL is required for MCP client'); } if (transport === 'streamablehttp') { return this.createStreamableHTTPClient(connectionId, url, options); } else if (transport === 'sse') { throw new Error('Legacy SSE transport not yet implemented. Use StreamableHTTP instead.'); } else { throw new Error(`Unsupported transport: ${transport}`); } } /** * Create a StreamableHTTP MCP client */ async createStreamableHTTPClient(connectionId, url, options) { const listeners = new Map(); const streamableTransport = new StreamableHTTPTransport(url, { onMessage: (message) => { this.notifyListeners(connectionId, 'message', { connectionId, message }); }, onError: (error) => { this.notifyListeners(connectionId, 'error', { connectionId, error }); }, onConnectionStateChange: (state) => { this.notifyListeners(connectionId, 'stateChange', { connectionId, state }); }, }, options.resumable || false, options.sessionId, options.lastSequence); const clientInfo = { connectionId, status: 'connecting', }; this.connections.set(connectionId, { transport: streamableTransport, info: clientInfo, listeners, }); // Send initialize request try { const initRequest = { jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: options.protocolVersion || '2025-03-26', clientInfo: options.clientInfo, capabilities: options.capabilities, }, }; await streamableTransport.sendMessage(initRequest, true); clientInfo.status = 'connected'; } catch (error) { clientInfo.status = 'error'; throw error; } return clientInfo; } /** * Send a message to an MCP server */ async sendMessage(connectionId, message, expectStream = false) { const connection = this.connections.get(connectionId); if (!connection) { throw new Error(`MCP connection not found: ${connectionId}`); } await connection.transport.sendMessage(message, expectStream); } /** * Open a listen stream for server-initiated messages */ async openListenStream(connectionId) { const connection = this.connections.get(connectionId); if (!connection) { throw new Error(`MCP connection not found: ${connectionId}`); } await connection.transport.openListenStream(); } /** * Close an MCP client connection */ closeClient(connectionId) { const connection = this.connections.get(connectionId); if (connection) { connection.transport.close(); connection.info.status = 'disconnected'; this.connections.delete(connectionId); } } /** * Get session information for a connection */ getSessionInfo(connectionId) { const connection = this.connections.get(connectionId); if (!connection) { return null; } return { sessionId: connection.transport.getSessionId(), lastSequence: connection.transport.getLastSequence(), resumable: connection.transport.isResumable(), }; } /** * Get client info */ getClientInfo(connectionId) { const connection = this.connections.get(connectionId); return connection ? connection.info : null; } /** * Add event listener */ addEventListener(connectionId, event, callback) { const connection = this.connections.get(connectionId); if (!connection) { throw new Error(`MCP connection not found: ${connectionId}`); } if (!connection.listeners.has(event)) { connection.listeners.set(event, new Set()); } connection.listeners.get(event).add(callback); } /** * Remove event listener */ removeEventListener(connectionId, event, callback) { const connection = this.connections.get(connectionId); if (!connection) { return; } const listeners = connection.listeners.get(event); if (listeners) { listeners.delete(callback); } } /** * Notify listeners */ notifyListeners(connectionId, event, data) { const connection = this.connections.get(connectionId); if (!connection) { return; } const listeners = connection.listeners.get(event); if (listeners) { listeners.forEach((callback) => { try { callback(data); } catch (error) { console.error('Error in MCP event listener:', error); } }); } } /** * Close all connections */ closeAll() { this.connections.forEach((connection, connectionId) => { this.closeClient(connectionId); }); } } // Export singleton instance export const mcpClientManager = new MCPClientManager();