@mcp-b/transports 0.0.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tab/TabClientTransport.ts","../src/tab/TabServerTransport.ts","../src/extension/backgroundBridge.ts","../src/extension/contentScript.ts","../src/extension/uiConnector.ts","../src/extension/extensionClientTransport.ts"],"names":["BrowserTransportError","code","message","DEFAULT_BROWSER_RECONNECTION_OPTIONS","TabClientTransport","opts","resumptionToken","resolve","reject","windowWithMcp","mcp","error","serverInfo","connectOptions","clientPort","handshakeComplete","handshakeTimer","event","data","replayEvent","eventMessage","JSONRPCMessageSchema","attempt","initialDelay","growFactor","maxDelay","lastEventId","maxRetries","delay","options","err","reconErr","namespace","InMemoryEventStore","maxEventsPerClient","streamId","clientId","eventId","clientEvents","e","eventsToRemove","send","startIndex","lastEventIndex","eventsToReplay","afterEventId","limit","events","afterIndex","TabServerTransport","mcpInterface","channel","serverPort","serverSessionId","connection","client","resumeFromEventId","port","clientInstanceId","isInitializeRequest","errMsg","serverInfoMessage","replayMessage","targetConnections","_","isJSONRPCResponse","isJSONRPCError","c","setupBackgroundBridge","uiPort","csPorts","clientTabMap","msgFromExtension","firstTabId","targetPort","tabId","disconnectedClientIds","msgFromTab","expectedTabId","mappedTabId","mcpRelay","csPort","msg","createUIBridge","handler","isJSONRPCMessage","value","DEFAULT_EXTENSION_RECONNECTION_OPTIONS","ExtensionClientTransport","resp","promise","eventMsg","signal","originalResolve","initialReconnectionDelay","maxReconnectionDelay","reconnectionDelayGrowFactor","tokenToResume"],"mappings":"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","file":"index.js","sourcesContent":["import { type Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { JSONRPCMessageSchema, type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';\nimport {\n type EventId,\n type MCPBrowserInterface,\n type MCPConnectOptions,\n type MCPEventMessage,\n type MCPReplayEventMessage,\n type MCPServerInfoMessage,\n type MCPWindow,\n} from '../browser-types.js';\n\n/**\n * Browser-specific error class to match StreamableHTTPError\n */\nexport class BrowserTransportError extends Error {\n constructor(\n public readonly code: string | undefined,\n message: string | undefined\n ) {\n super(`Browser transport error: ${message}`);\n }\n}\n\n/**\n * Configuration options for the BrowserClientTransport, matching StreamableHTTPClientTransportOptions style\n */\nexport interface TabClientTransportOptions {\n /**\n * A unique identifier for this client instance. If not provided, one will be generated.\n * This is similar to a persistent client identifier.\n */\n clientInstanceId?: string;\n\n /**\n * Global namespace to look for MCP server (defaults to 'mcp')\n */\n globalNamespace?: string;\n\n /**\n * Options to configure the reconnection behavior.\n */\n reconnectionOptions?: BrowserReconnectionOptions;\n\n /**\n * Timeout for initial connection handshake (ms). Default is 30000 (30 seconds).\n */\n connectionTimeout?: number;\n}\n\n/**\n * Configuration options for reconnection behavior\n */\nexport interface BrowserReconnectionOptions {\n /**\n * Maximum backoff time between reconnection attempts in milliseconds.\n * Default is 30000 (30 seconds).\n */\n maxReconnectionDelay: number;\n\n /**\n * Initial backoff time between reconnection attempts in milliseconds.\n * Default is 1000 (1 second).\n */\n initialReconnectionDelay: number;\n\n /**\n * The factor by which the reconnection delay increases after each attempt.\n * Default is 1.5.\n */\n reconnectionDelayGrowFactor: number;\n\n /**\n * Maximum number of reconnection attempts before giving up.\n * Default is 2.\n */\n maxRetries: number;\n}\n\n// Default reconnection options matching StreamableHTTP\nconst DEFAULT_BROWSER_RECONNECTION_OPTIONS: BrowserReconnectionOptions = {\n initialReconnectionDelay: 1000,\n maxReconnectionDelay: 30000,\n reconnectionDelayGrowFactor: 1.5,\n maxRetries: 2,\n};\n\n/**\n * Client transport for browser environments using window.mcp global.\n * This implementation follows the same patterns as StreamableHTTPClientTransport.\n */\nexport class TabClientTransport implements Transport {\n private _globalNamespace: string;\n /**\n * The client's persistent instance ID\n */\n public clientInstanceId: string;\n /**\n * The session ID provided by the server during connection\n */\n public sessionId?: string;\n private _reconnectionOptions: BrowserReconnectionOptions;\n private _connectionTimeout: number;\n\n private _port?: MessagePort;\n /**\n * The server's instance ID, received during handshake.\n */\n public serverInstanceId?: string;\n public hasEventStore: boolean = false;\n public streamId?: string;\n /**\n * Indicates whether the transport is currently connected.\n */\n public isConnected: boolean = false;\n private _abortController?: AbortController; // For consistency with StreamableHTTP\n private _connectionPromise?: {\n resolve: () => void;\n reject: (error: Error) => void;\n };\n /**\n * The last event ID received from the server.\n */\n public lastEventId?: EventId;\n private _reconnectAttempt: number = 0;\n\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n constructor(opts?: TabClientTransportOptions) {\n this._globalNamespace = opts?.globalNamespace ?? 'mcp';\n this._reconnectionOptions = opts?.reconnectionOptions ?? DEFAULT_BROWSER_RECONNECTION_OPTIONS;\n this._connectionTimeout = opts?.connectionTimeout ?? 30000;\n\n this.clientInstanceId =\n opts?.clientInstanceId ||\n (typeof crypto !== 'undefined' && crypto.randomUUID\n ? crypto.randomUUID()\n : `client-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`);\n }\n\n /**\n * Start the transport connection\n */\n async start(): Promise<void> {\n if (this._abortController) {\n throw new Error(\n 'TabClientTransport already started! If using Client class, note that connect() calls start() automatically.'\n );\n }\n\n this._abortController = new AbortController();\n await this._connectWithRetry();\n }\n\n /**\n * Internal method to establish connection with retry logic\n */\n private async _connectWithRetry(resumptionToken?: EventId): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this._connectionPromise = { resolve, reject };\n\n const windowWithMcp = window as MCPWindow;\n const mcp: MCPBrowserInterface | undefined =\n this._globalNamespace === 'mcp'\n ? windowWithMcp.mcp\n : (windowWithMcp as any)[this._globalNamespace];\n\n if (!mcp?.isServerAvailable?.()) {\n const error = new BrowserTransportError(\n 'NO_SERVER',\n `No MCP server found at window.${this._globalNamespace}`\n );\n this._handleConnectionError(error, resumptionToken);\n return;\n }\n\n // Get server info\n const serverInfo = mcp.getServerInfo();\n this.serverInstanceId = serverInfo.instanceId;\n\n // Request connection with optional resume\n const connectOptions: MCPConnectOptions | undefined = resumptionToken\n ? { resumeFrom: resumptionToken }\n : undefined;\n\n const clientPort = mcp.connect(this.clientInstanceId, connectOptions);\n if (!clientPort) {\n const error = new BrowserTransportError(\n 'CONNECTION_FAILED',\n 'Failed to connect to MCP server'\n );\n this._handleConnectionError(error, resumptionToken);\n return;\n }\n\n this._port = clientPort;\n let handshakeComplete = false;\n let handshakeTimer: ReturnType<typeof setTimeout>;\n\n // Set up message handling\n this._port.onmessage = (event: MessageEvent) => {\n const data = event.data;\n\n // Handle server info handshake\n if (!handshakeComplete && data.type === 'mcp-server-info') {\n const serverInfo = data as MCPServerInfoMessage;\n clearTimeout(handshakeTimer);\n handshakeComplete = true;\n this.sessionId = serverInfo.serverSessionId;\n this.hasEventStore = serverInfo.hasEventStore || false;\n this.streamId = serverInfo.streamId;\n this.isConnected = true;\n this._reconnectAttempt = 0; // Reset on successful connection\n\n if (this._connectionPromise) {\n this._connectionPromise.resolve();\n this._connectionPromise = undefined;\n }\n return;\n }\n\n // Handle replay events during resumption\n if (data.type === 'mcp-replay-event') {\n const replayEvent = data as MCPReplayEventMessage;\n this.lastEventId = replayEvent.eventId;\n this._handleMessage(replayEvent.message);\n return;\n }\n\n // Handle regular events with event IDs\n if (data.type === 'mcp-event') {\n const eventMessage = data as MCPEventMessage;\n this.lastEventId = eventMessage.eventId;\n this._handleMessage(eventMessage.message);\n return;\n }\n\n // Handle regular JSON-RPC messages (backward compatibility)\n if (handshakeComplete) {\n this._handleMessage(data);\n }\n };\n\n this._port.onmessageerror = () => {\n const error = new BrowserTransportError('MESSAGE_ERROR', 'MessagePort error');\n this.onerror?.(error);\n if (this._connectionPromise) {\n this._connectionPromise.reject(error);\n this._connectionPromise = undefined;\n }\n };\n\n // Note: MessagePort doesn't have an onclose event\n // Connection loss will be detected through other means (e.g., send failures)\n\n // Start the port\n this._port.start();\n\n // Set handshake timeout\n handshakeTimer = setTimeout(() => {\n if (!handshakeComplete) {\n const error = new BrowserTransportError('HANDSHAKE_TIMEOUT', 'Server handshake timeout');\n this._handleConnectionError(error, resumptionToken);\n }\n }, this._connectionTimeout);\n });\n }\n\n /**\n * Handle incoming messages with error handling\n */\n private _handleMessage(data: unknown): void {\n try {\n const message = JSONRPCMessageSchema.parse(data);\n this.onmessage?.(message);\n } catch (error) {\n this.onerror?.(new Error(`Failed to parse message: ${error}`));\n }\n }\n\n /**\n * Handle connection errors with retry logic\n */\n private _handleConnectionError(error: Error, resumptionToken?: EventId): void {\n this.onerror?.(error);\n\n if (this._connectionPromise) {\n this._connectionPromise.reject(error);\n this._connectionPromise = undefined;\n }\n\n // Schedule reconnection if appropriate\n if (this._abortController && !this._abortController.signal.aborted && resumptionToken) {\n this._scheduleReconnection(resumptionToken);\n }\n }\n\n /**\n * Calculate the next reconnection delay using exponential backoff\n */\n private _getNextReconnectionDelay(attempt: number): number {\n const initialDelay = this._reconnectionOptions.initialReconnectionDelay;\n const growFactor = this._reconnectionOptions.reconnectionDelayGrowFactor;\n const maxDelay = this._reconnectionOptions.maxReconnectionDelay;\n\n return Math.min(initialDelay * Math.pow(growFactor, attempt), maxDelay);\n }\n\n /**\n * Schedule a reconnection attempt with exponential backoff\n */\n private _scheduleReconnection(lastEventId: EventId): void {\n const maxRetries = this._reconnectionOptions.maxRetries;\n\n if (maxRetries > 0 && this._reconnectAttempt >= maxRetries) {\n this.onerror?.(new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));\n return;\n }\n\n const delay = this._getNextReconnectionDelay(this._reconnectAttempt);\n\n setTimeout(() => {\n this._reconnectAttempt++;\n this._connectWithRetry(lastEventId).catch((error) => {\n this.onerror?.(\n new Error(\n `Failed to reconnect: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n });\n }, delay);\n }\n\n /**\n * Send a message over the transport\n */\n async send(\n message: JSONRPCMessage,\n options?: {\n resumptionToken?: string;\n onresumptiontoken?: (token: string) => void;\n }\n ): Promise<void> {\n if (!this.isConnected || !this._port) {\n // Handle resumption case with explicit token\n if (options?.resumptionToken) {\n await this._connectWithRetry(options.resumptionToken).catch((err) => {\n this.onerror?.(\n new Error(\n `Failed to reconnect with token: ${err instanceof Error ? err.message : String(err)}`\n )\n );\n throw err;\n });\n if (!this.isConnected || !this._port) {\n throw new Error('Not connected after attempting reconnection with token.');\n }\n } else if (\n this._reconnectionOptions.maxRetries > 0 &&\n this.lastEventId &&\n this._abortController &&\n !this._abortController.signal.aborted\n ) {\n // Attempt auto-reconnection if disconnected, retries enabled, and lastEventId known\n await this._connectWithRetry(this.lastEventId).catch((err) => {\n const reconErr = new Error(\n `Failed to auto-reconnect: ${err instanceof Error ? err.message : String(err)}`\n );\n this.onerror?.(reconErr);\n throw reconErr;\n });\n if (!this.isConnected || !this._port) {\n throw new Error('Not connected after attempting auto-reconnection.');\n }\n } else {\n throw new Error('Not connected');\n }\n }\n\n // For browser transport, we just send the message directly\n // The event ID tracking is handled automatically by the server\n this._port.postMessage(message);\n }\n\n /**\n * Close the transport connection\n */\n async close(): Promise<void> {\n // Abort any pending operations\n this._abortController?.abort();\n this._abortController = undefined;\n\n if (this._connectionPromise) {\n this._connectionPromise.reject(new Error('Transport closed'));\n this._connectionPromise = undefined;\n }\n\n if (this._port) {\n this._port.close();\n this._port = undefined;\n }\n\n // Notify server of disconnection\n const windowWithMcp = window as MCPWindow;\n const mcp: MCPBrowserInterface | undefined =\n this._globalNamespace === 'mcp'\n ? windowWithMcp.mcp\n : (windowWithMcp as any)[this._globalNamespace];\n\n if (mcp?.disconnect) {\n mcp.disconnect(this.clientInstanceId);\n }\n\n this.isConnected = false;\n this.onclose?.();\n }\n\n /**\n * Terminate the current session explicitly\n * Similar to StreamableHTTP's terminateSession\n */\n async terminateSession(): Promise<void> {\n if (!this.sessionId) {\n return; // No session to terminate\n }\n\n try {\n // Use the new terminateSession for full cleanup if available\n const windowWithMcp = window as MCPWindow;\n const mcp: MCPBrowserInterface | undefined =\n this._globalNamespace === 'mcp'\n ? windowWithMcp.mcp\n : (windowWithMcp as any)[this._globalNamespace];\n\n if (mcp?.terminateSession) {\n mcp.terminateSession(this.clientInstanceId);\n } else if (mcp?.events?.clearEvents) {\n // Fallback to just clearing events if terminate is not implemented\n mcp.events.clearEvents(this.clientInstanceId);\n }\n\n this.sessionId = undefined;\n this.lastEventId = undefined;\n } catch (error) {\n this.onerror?.(error as Error);\n throw error;\n }\n }\n\n /**\n * Static helper to check if an MCP server is available\n * Similar to checking server availability before connection\n */\n static isServerAvailable(namespace: string = 'mcp'): boolean {\n const windowWithMcp = window as MCPWindow;\n const mcp: MCPBrowserInterface | undefined =\n namespace === 'mcp' ? windowWithMcp.mcp : (windowWithMcp as any)[namespace];\n\n return !!mcp?.isServerAvailable?.();\n }\n}\n","import { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js';\nimport { Transport, TransportSendOptions } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport {\n isInitializeRequest,\n isJSONRPCError,\n isJSONRPCResponse,\n JSONRPCMessage,\n JSONRPCMessageSchema,\n RequestId,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n EventId,\n MCPBrowserInterface,\n MCPConnectOptions,\n MCPEventMessage,\n MCPReplayEventMessage,\n MCPServerInfo,\n MCPServerInfoMessage,\n MCPWindow,\n StoredEvent,\n StreamId,\n} from '../browser-types.js';\n\n/**\n * In-memory event store implementation\n */\nclass InMemoryEventStore {\n private _events: StoredEvent[] = [];\n private _eventCounter: number = 0;\n private _maxEventsPerClient: number;\n\n constructor(maxEventsPerClient: number = 1000) {\n this._maxEventsPerClient = maxEventsPerClient;\n }\n\n async storeEvent(\n streamId: StreamId,\n clientId: string,\n message: JSONRPCMessage\n ): Promise<EventId> {\n const eventId = `evt_${++this._eventCounter}_${Date.now()}`;\n const event: StoredEvent = {\n eventId,\n streamId,\n message,\n timestamp: Date.now(),\n clientId,\n };\n\n this._events.push(event);\n\n // Cleanup old events for this client if limit exceeded\n const clientEvents = this._events.filter((e) => e.clientId === clientId);\n if (clientEvents.length > this._maxEventsPerClient) {\n const eventsToRemove = clientEvents.slice(0, clientEvents.length - this._maxEventsPerClient);\n this._events = this._events.filter((e) => !eventsToRemove.includes(e));\n }\n\n return eventId;\n }\n\n async replayEventsAfter(\n clientId: string,\n lastEventId: EventId | undefined,\n send: (eventId: EventId, message: JSONRPCMessage) => Promise<void>\n ): Promise<StreamId> {\n const clientEvents = this._events.filter((e) => e.clientId === clientId);\n\n let startIndex = 0;\n if (lastEventId) {\n const lastEventIndex = clientEvents.findIndex((e) => e.eventId === lastEventId);\n if (lastEventIndex >= 0) {\n startIndex = lastEventIndex + 1;\n }\n }\n\n const eventsToReplay = clientEvents.slice(startIndex);\n for (const event of eventsToReplay) {\n await send(event.eventId, event.message);\n }\n\n // Return the stream ID from the last replayed event, or generate new one\n return eventsToReplay.length > 0\n ? eventsToReplay[eventsToReplay.length - 1].streamId\n : `stream_${Date.now()}`;\n }\n\n getEvents(clientId?: string, afterEventId?: EventId, limit: number = 100): StoredEvent[] {\n let events = clientId ? this._events.filter((e) => e.clientId === clientId) : this._events;\n\n if (afterEventId) {\n const afterIndex = events.findIndex((e) => e.eventId === afterEventId);\n if (afterIndex >= 0) {\n events = events.slice(afterIndex + 1);\n }\n }\n\n return events.slice(0, limit);\n }\n\n getLastEventId(clientId?: string): EventId | null {\n const events = clientId ? this._events.filter((e) => e.clientId === clientId) : this._events;\n\n return events.length > 0 ? events[events.length - 1].eventId : null;\n }\n\n clearEvents(clientId?: string): void {\n if (clientId) {\n this._events = this._events.filter((e) => e.clientId !== clientId);\n } else {\n this._events = [];\n }\n }\n\n removeClientEvents(clientId: string): void {\n this._events = this._events.filter((e) => e.clientId !== clientId);\n }\n}\n\n/**\n * Configuration options for BrowserServerTransport\n */\nexport interface BrowserServerTransportOptions {\n /**\n * Function that generates a session ID for each client connection.\n * Return undefined to operate in stateless mode.\n * If not provided, defaults to undefined (stateless mode).\n */\n sessionIdGenerator?: (() => string) | undefined;\n\n /**\n * Callback for session initialization events\n */\n onsessioninitialized?: (clientSessionId: string | undefined, clientInstanceId: string) => void;\n\n /**\n * Optional namespace to use instead of window.mcp\n */\n globalNamespace?: string;\n\n /**\n * Enable event storage for resumability (only works in stateful mode)\n * Default is true in stateful mode, false in stateless mode\n */\n enableEventStore?: boolean;\n\n /**\n * Maximum number of events to store per client (default: 1000)\n */\n maxEventsPerClient?: number;\n}\n\ninterface ClientConnection {\n port: MessagePort;\n clientInstanceId: string;\n serverSessionId?: string;\n streamId: StreamId;\n initialized: boolean;\n requestIds: Set<RequestId>;\n}\n\n/**\n * Server transport for browser environments using window.mcp global\n * Supports multiple concurrent client connections via MessageChannel\n */\nexport class TabServerTransport implements Transport {\n private _serverInstanceId: string;\n private _sessionIdGenerator: (() => string) | undefined;\n private _onsessioninitialized?: (\n clientSessionId: string | undefined,\n clientInstanceId: string\n ) => void;\n\n private _isStarted: boolean = false;\n private _clients: Map<string, ClientConnection> = new Map();\n private _globalNamespace: string;\n private _eventStore?: InMemoryEventStore;\n private _enableEventStore: boolean;\n\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage, extra?: { authInfo?: AuthInfo | undefined }) => void;\n\n constructor(options?: BrowserServerTransportOptions) {\n this._sessionIdGenerator = options?.sessionIdGenerator;\n this._onsessioninitialized = options?.onsessioninitialized;\n this._globalNamespace = options?.globalNamespace || 'mcp';\n\n // Event store is enabled by default in stateful mode\n this._enableEventStore = options?.enableEventStore ?? this._sessionIdGenerator !== undefined;\n\n if (this._enableEventStore && this._sessionIdGenerator) {\n this._eventStore = new InMemoryEventStore(options?.maxEventsPerClient);\n }\n\n this._serverInstanceId =\n typeof crypto !== 'undefined' && crypto.randomUUID\n ? crypto.randomUUID()\n : `server-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n\n async start(): Promise<void> {\n if (this._isStarted) {\n throw new Error('BrowserServerTransport already started');\n }\n\n // Check if another server is already registered\n const windowWithMcp = window as MCPWindow;\n const existingMcp =\n this._globalNamespace === 'mcp'\n ? windowWithMcp.mcp\n : (windowWithMcp as any)[this._globalNamespace];\n if (existingMcp?.isServerAvailable?.()) {\n throw new Error(\n `Another MCP server is already registered at window.${this._globalNamespace}`\n );\n }\n\n const mcpInterface: MCPBrowserInterface = {\n connect: (clientId: string, options?: MCPConnectOptions): MessagePort | null => {\n if (!this._isStarted) {\n console.error('MCP server not started');\n return null;\n }\n\n if (this._clients.has(clientId)) {\n console.error(`Client ${clientId} already connected`);\n return null;\n }\n\n const channel = new MessageChannel();\n const serverPort = channel.port1;\n const clientPort = channel.port2;\n\n const serverSessionId = this._sessionIdGenerator?.();\n const streamId = `stream_${clientId}_${Date.now()}`;\n\n const connection: ClientConnection = {\n port: serverPort,\n clientInstanceId: clientId,\n serverSessionId,\n streamId,\n initialized: false,\n requestIds: new Set(),\n };\n\n this._setupClientConnection(connection, options?.resumeFrom);\n this._clients.set(clientId, connection);\n\n return clientPort;\n },\n\n disconnect: (clientId: string): void => {\n const client = this._clients.get(clientId);\n if (client) {\n client.port.close();\n this._clients.delete(clientId);\n // Note: We keep events for disconnected clients for resumability\n }\n },\n\n isServerAvailable: (): boolean => {\n return this._isStarted;\n },\n\n getServerInfo: (): MCPServerInfo => ({\n instanceId: this._serverInstanceId,\n stateful: this._sessionIdGenerator !== undefined,\n hasEventStore: this._eventStore !== undefined,\n }),\n\n terminateSession: (clientId: string): void => {\n const client = this._clients.get(clientId);\n if (client) {\n client.port.close();\n this._clients.delete(clientId);\n }\n this._eventStore?.removeClientEvents(clientId);\n },\n };\n\n // Add event storage interface if enabled\n if (this._eventStore) {\n mcpInterface.events = {\n getEvents: (clientId?: string, afterEventId?: EventId, limit?: number) => {\n return this._eventStore!.getEvents(clientId, afterEventId, limit);\n },\n getLastEventId: (clientId?: string) => {\n return this._eventStore!.getLastEventId(clientId);\n },\n clearEvents: (clientId?: string) => {\n this._eventStore!.clearEvents(clientId);\n },\n };\n }\n\n if (this._globalNamespace === 'mcp') {\n (window as MCPWindow).mcp = mcpInterface;\n } else {\n (window as any)[this._globalNamespace] = mcpInterface;\n }\n this._isStarted = true;\n }\n\n private async _setupClientConnection(\n connection: ClientConnection,\n resumeFromEventId?: EventId\n ): Promise<void> {\n const { port, clientInstanceId } = connection;\n\n port.onmessage = (event: MessageEvent) => {\n try {\n const message = JSONRPCMessageSchema.parse(event.data);\n\n // Track request IDs from this client\n if ('id' in message && message.id !== undefined && 'method' in message) {\n connection.requestIds.add(message.id);\n }\n\n const isInitReq = isInitializeRequest(message);\n\n if (isInitReq) {\n if (connection.initialized) {\n this.onerror?.(new Error(`Client ${clientInstanceId} attempted to re-initialize`));\n return;\n }\n connection.initialized = true;\n this._onsessioninitialized?.(connection.serverSessionId, clientInstanceId);\n } else if (!connection.initialized) {\n const errMsg = `Client ${clientInstanceId} sent message before initialization`;\n this.onerror?.(new Error(errMsg));\n return;\n }\n\n this.onmessage?.(message, {\n authInfo: {\n clientId: clientInstanceId,\n token: 'N/A',\n scopes: ['browser'],\n },\n });\n } catch (error) {\n this.onerror?.(error instanceof Error ? error : new Error(String(error)));\n }\n };\n\n port.onmessageerror = () => {\n this.onerror?.(new Error(`MessagePort error for client ${clientInstanceId}`));\n };\n\n port.start();\n\n // Send initial server info\n const serverInfoMessage: MCPServerInfoMessage = {\n type: 'mcp-server-info',\n serverInstanceId: this._serverInstanceId,\n serverSessionId: connection.serverSessionId,\n hasEventStore: this._eventStore !== undefined,\n streamId: connection.streamId,\n };\n port.postMessage(serverInfoMessage);\n\n // Replay events if resuming\n if (resumeFromEventId && this._eventStore) {\n await this._eventStore.replayEventsAfter(\n clientInstanceId,\n resumeFromEventId,\n async (eventId: EventId, message: JSONRPCMessage) => {\n const replayMessage: MCPReplayEventMessage = {\n type: 'mcp-replay-event',\n eventId,\n message,\n };\n port.postMessage(replayMessage);\n }\n );\n }\n }\n\n async send(\n message: JSONRPCMessage,\n options?: TransportSendOptions & { targetClientId?: string }\n ): Promise<void> {\n if (!this._isStarted) {\n throw new Error('BrowserServerTransport not started');\n }\n\n let targetConnections: ClientConnection[] = [];\n\n // Determine target client(s)\n if (options?.relatedRequestId) {\n // Find client that made this request\n for (const [_, connection] of this._clients) {\n if (connection.requestIds.has(options.relatedRequestId)) {\n targetConnections = [connection];\n // Clean up request ID if this is a response\n if (isJSONRPCResponse(message) || isJSONRPCError(message)) {\n connection.requestIds.delete(options.relatedRequestId);\n }\n break;\n }\n }\n } else if (options?.targetClientId) {\n const connection = this._clients.get(options.targetClientId);\n if (connection) {\n targetConnections = [connection];\n }\n } else {\n // Broadcast to all initialized clients\n targetConnections = Array.from(this._clients.values()).filter((c) => c.initialized);\n }\n\n if (targetConnections.length === 0) {\n this.onerror?.(new Error('No suitable clients found for message'));\n return;\n }\n\n for (const connection of targetConnections) {\n // Store event if event store is enabled\n let eventId: EventId | undefined;\n if (this._eventStore) {\n eventId = await this._eventStore.storeEvent(\n connection.streamId,\n connection.clientInstanceId,\n message\n );\n }\n\n // Send message with event ID if available\n if (eventId) {\n const eventMessage: MCPEventMessage = {\n type: 'mcp-event',\n eventId,\n message,\n };\n connection.port.postMessage(eventMessage);\n } else {\n connection.port.postMessage(message);\n }\n }\n }\n\n async close(): Promise<void> {\n if (!this._isStarted) {\n return;\n }\n\n // Close all client connections\n for (const connection of this._clients.values()) {\n connection.port.close();\n }\n this._clients.clear();\n\n // Clear all events\n this._eventStore?.clearEvents();\n\n // Remove global interface\n if (this._globalNamespace === 'mcp') {\n delete (window as MCPWindow).mcp;\n } else {\n delete (window as any)[this._globalNamespace];\n }\n\n this._isStarted = false;\n this.onclose?.();\n }\n\n get clientCount(): number {\n return this._clients.size;\n }\n\n get clients(): ReadonlyArray<{\n clientId: string;\n initialized: boolean;\n serverSessionId?: string;\n }> {\n return Array.from(this._clients.entries()).map(([clientId, connection]) => ({\n clientId,\n initialized: connection.initialized,\n serverSessionId: connection.serverSessionId,\n }));\n }\n}\n","import { type BridgeMessage, type BridgeResponse } from './uiConnector.js';\n\n/**\n * In your background script:\n * import { setupBackgroundBridge } from '@modelcontextprotocol/sdk/extension-bridge/backgroundBridge'\n * // Dynamically inject pageBridge and contentScript into matching pages\n * setupBackgroundBridge({\n * matches: ['https://your-app.com/*'],\n * pageBridgeRunAt: 'document_start',\n * contentScriptRunAt: 'document_idle'\n * });\n */\nexport async function setupBackgroundBridge(_?: {\n /** Host-match patterns for injection, defaults to ['<all_urls>'] */\n matches?: string[];\n /** When to inject the pageBridge (MAIN world) */\n pageBridgeRunAt?: 'document_start' | 'document_end' | 'document_idle';\n /** When to inject the content script (ISOLATED world) */\n contentScriptRunAt?: 'document_start' | 'document_end' | 'document_idle';\n}): Promise<void> {\n // // Dynamically register content scripts if the scripting API is available (MV3+)\n // if (chrome.scripting?.registerContentScripts) {\n // const matches = options?.matches ?? ['<all_urls>'];\n // chrome.scripting.registerContentScripts([{\n // id: 'mcp-page-bridge',\n // js: ['extension-bridge/pageBridge.js'],\n // matches,\n // runAt: options?.pageBridgeRunAt ?? 'document_start',\n // world: 'MAIN',\n // persistAcrossSessions: true\n // }, {\n // id: 'mcp-content-script',\n // js: ['extension-bridge/contentScript.js'],\n // matches,\n // runAt: options?.contentScriptRunAt ?? 'document_idle',\n // world: 'ISOLATED',\n // persistAcrossSessions: true\n // }]);\n // }\n let uiPort: chrome.runtime.Port | null = null;\n const csPorts = new Map<number, chrome.runtime.Port>();\n\n // Map client IDs to specific tab IDs to ensure proper routing\n const clientTabMap = new Map<string, number>();\n\n console.log('BSGW: Background bridge initialized');\n\n chrome.runtime.onConnect.addListener((port) => {\n if (port.name === 'extensionUI') {\n console.log('BSGW: Extension UI connected');\n uiPort = port;\n\n port.onMessage.addListener((msgFromExtension: BridgeMessage) => {\n console.log('BSGW: Message from extension', msgFromExtension);\n\n if (msgFromExtension.cmd === 'connect') {\n // For connect commands, we need to pick a tab to connect to\n // For now, use the first available tab, but this could be made smarter\n const firstTabId = Array.from(csPorts.keys())[0];\n if (firstTabId !== undefined) {\n clientTabMap.set(msgFromExtension.clientId, firstTabId);\n const targetPort = csPorts.get(firstTabId);\n if (targetPort) {\n console.log(\n `BSGW: Routing connect for client ${msgFromExtension.clientId} to tab ${firstTabId}`\n );\n targetPort.postMessage(msgFromExtension);\n }\n } else {\n console.error('BSGW: No content script tabs available for connection');\n }\n } else if (msgFromExtension.cmd === 'send') {\n // For send commands, route to the tab that this client is connected to\n const tabId = clientTabMap.get(msgFromExtension.clientId);\n if (tabId !== undefined) {\n const targetPort = csPorts.get(tabId);\n if (targetPort) {\n console.log(\n `BSGW: Routing send for client ${msgFromExtension.clientId} to tab ${tabId}`\n );\n targetPort.postMessage(msgFromExtension);\n } else {\n console.error(\n `BSGW: Tab ${tabId} no longer available for client ${msgFromExtension.clientId}`\n );\n clientTabMap.delete(msgFromExtension.clientId);\n }\n } else {\n console.error(`BSGW: No tab mapping found for client ${msgFromExtension.clientId}`);\n }\n }\n });\n\n // In backgroundBridge.ts\n\n port.onDisconnect.addListener(() => {\n console.log('BSGW: Extension UI disconnected');\n\n // Find all clients that were connected through this UI port\n const disconnectedClientIds = new Set<string>();\n for (const [clientId, _] of clientTabMap.entries()) {\n // This logic assumes one UI port. If you have multiple, you'll need to\n // map UI ports to clients. For now, let's assume one.\n disconnectedClientIds.add(clientId);\n }\n\n disconnectedClientIds.forEach((clientId) => {\n const tabId = clientTabMap.get(clientId);\n if (tabId !== undefined) {\n const targetPort = csPorts.get(tabId);\n if (targetPort) {\n // Send a new 'disconnect' command to the content script\n console.log(`BSGW: Relaying disconnect for client ${clientId} to tab ${tabId}`);\n targetPort.postMessage({ cmd: 'disconnect', clientId });\n }\n }\n // Clean up the mapping in the background script\n clientTabMap.delete(clientId);\n });\n\n uiPort = null;\n });\n } else if (port.name === 'cs') {\n const tabId = port.sender?.tab?.id;\n if (typeof tabId === 'number') {\n console.log(`BSGW: Content script connected from tab ${tabId}`);\n csPorts.set(tabId, port);\n\n port.onMessage.addListener((msgFromTab: BridgeResponse) => {\n console.log(`BSGW: Message from tab ${tabId}`, msgFromTab);\n\n // Only forward if this response is from the tab we expect for this client\n const expectedTabId = clientTabMap.get(msgFromTab.clientId);\n if (expectedTabId === tabId) {\n uiPort?.postMessage(msgFromTab);\n } else {\n console.warn(\n `BSGW: Ignoring response from tab ${tabId} for client ${msgFromTab.clientId} (expected tab ${expectedTabId})`\n );\n }\n });\n\n port.onDisconnect.addListener(() => {\n console.log(`BSGW: Content script disconnected from tab ${tabId}`);\n csPorts.delete(tabId);\n\n // Clean up any client mappings to this tab\n for (const [clientId, mappedTabId] of clientTabMap.entries()) {\n if (mappedTabId === tabId) {\n console.log(`BSGW: Removing client ${clientId} mapping to disconnected tab ${tabId}`);\n\n // NOTIFY THE UI: Tell the extension UI that the server for this specific\n // client has disappeared.\n if (uiPort) {\n console.log(`BSGW: Notifying UI about disconnected client ${clientId}`);\n uiPort.postMessage({\n clientId: clientId, // Target the specific client instance\n msg: {\n type: 'mcp-server-disconnected',\n reason: `The tab hosting the server was refreshed or closed.`,\n },\n });\n }\n\n clientTabMap.delete(clientId);\n }\n }\n });\n }\n }\n });\n}\n","import { type BridgeMessage, type PageBridgeMessageType } from './uiConnector.js';\n\n/**\n * Sets up a content script bridge that relays messages between the page context\n * and the extension background script. This enables communication between\n * the injected page bridge and the extension's background script.\n *\n * @param port - Optional Chrome runtime port. If not provided, creates a default port with name 'cs'\n * @returns The Chrome runtime port used for communication\n */\nexport function mcpRelay(port?: chrome.runtime.Port): chrome.runtime.Port {\n // Use provided port or create default connection to background script\n const csPort = port ?? chrome.runtime.connect({ name: 'cs' });\n\n // Relay messages from page context to extension background\n // Listen for messages from the injected page bridge (pageBridge.js)\n window.addEventListener('message', (e: MessageEvent) => {\n if (e.source === window && e.data?.source === 'EXT-PAGE') {\n console.log('MCP relay: received from tab', e.data.cmd, e.data.clientId);\n const { clientId, msg } = e.data as {\n clientId: string;\n msg: PageBridgeMessageType;\n };\n csPort.postMessage({ clientId, msg });\n }\n });\n\n // Relay messages from extension background to page context\n // Forward messages from background script to the page bridge\n csPort.onMessage.addListener((data: BridgeMessage) => {\n console.log('MCP relay: received from extension', data.cmd, data.clientId);\n window.postMessage({ source: 'EXT-CS', ...data }, '*');\n });\n\n return csPort;\n}\n","import { type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';\nimport {\n type MCPConnectOptions,\n type MCPEventMessage,\n type MCPReplayEventMessage,\n type MCPServerInfoMessage,\n} from '../browser-types';\n\n/**\n * Union type representing all possible message types that can be sent through the page bridge.\n * This includes MCP server information, events, replay events, and JSON-RPC messages.\n */\nexport type PageBridgeMessageType =\n | MCPServerInfoMessage\n | MCPEventMessage\n | MCPReplayEventMessage\n | JSONRPCMessage\n | {\n type: 'mcp-server-disconnected';\n reason: string;\n };\n\n/**\n * Response structure for messages received from the bridge.\n */\nexport interface BridgeResponse {\n /** Unique identifier for the client connection */\n clientId: string;\n /** The actual message payload */\n msg: PageBridgeMessageType;\n}\n\n/**\n * Message structure for commands sent to the bridge.\n */\nexport interface BridgeMessage {\n /** Command type - either 'connect' to establish a connection or 'send' to send a message */\n cmd: 'connect' | 'send' | 'disconnect';\n /** Unique identifier for the client connection */\n clientId: string;\n /** Connection options, required when cmd is 'connect' */\n options?: MCPConnectOptions;\n /** JSON-RPC message to send, required when cmd is 'send' */\n message?: JSONRPCMessage;\n}\n\n/**\n * Creates a UI bridge for communicating with MCP servers from browser extension UI components.\n *\n * This function establishes a connection to the extension's background script via Chrome's\n * runtime messaging API, allowing UI components like sidebars and popups to interact with\n * MCP servers.\n *\n * @param port - Optional Chrome runtime port to use for communication. If not provided,\n * a new port will be created with the name 'extensionUI'.\n *\n * The port should be connected to your background script's chrome.runtime.onConnect listener.\n *\n * @returns An object with methods to interact with MCP servers:\n * - connect: Establish a connection to an MCP server\n * - send: Send JSON-RPC messages to a connected server\n * - onMessage: Listen for responses and events from the server\n *\n * @example\n * ```typescript\n * // In your sidebar/popup code:\n * import { createUIBridge } from '@modelcontextprotocol/sdk/extension-bridge/uiConnector';\n *\n * // Using default port\n * const bridge = createUIBridge();\n *\n * // Or using a custom port\n * const customPort = chrome.runtime.connect({ name: 'sidebar' });\n * const bridge = createUIBridge(customPort);\n *\n * // Connect to an MCP server\n * bridge.connect('my-client-id', {\n * serverName: 'my-server',\n * command: 'node',\n * args: ['server.js']\n * });\n *\n * // Listen for messages\n * bridge.onMessage((response) => {\n * console.log('Received:', response.msg);\n * });\n *\n * // Send a message\n * bridge.send('my-client-id', {\n * jsonrpc: '2.0',\n * id: 1,\n * method: 'tools/list'\n * });\n * ```\n */\nexport function createUIBridge(\n port: chrome.runtime.Port = chrome.runtime.connect({ name: 'extensionUI' })\n) {\n return {\n /**\n * Establishes a connection to an MCP server.\n *\n * @param clientId - Unique identifier for this client connection\n * @param options - Configuration options for the MCP server connection\n */\n connect: (clientId: string, options?: MCPConnectOptions) => {\n console.log({ clientId, options });\n port.postMessage({ cmd: 'connect', clientId, options });\n },\n\n /**\n * Sends a JSON-RPC message to a connected MCP server.\n *\n * @param clientId - The client ID of the connection to send the message through\n * @param message - The JSON-RPC message to send\n */\n send: (clientId: string, message: JSONRPCMessage) => {\n console.log({ clientId, message });\n port.postMessage({ cmd: 'send', clientId, message });\n },\n\n /**\n * Registers a handler for incoming messages from MCP servers.\n *\n * @param handler - Function to handle incoming bridge responses\n */\n onMessage: (handler: (resp: BridgeResponse) => void) => {\n port.onMessage.addListener(handler);\n },\n };\n}\n","import {\n type Transport,\n type TransportSendOptions,\n} from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { JSONRPCMessageSchema, type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';\nimport {\n type EventId,\n type MCPConnectOptions,\n type MCPEventMessage,\n type MCPReplayEventMessage,\n type MCPServerInfoMessage,\n} from '../browser-types';\nimport { createUIBridge, type BridgeResponse, type PageBridgeMessageType } from './uiConnector.js';\n\nexport const isJSONRPCMessage = (value: unknown): value is JSONRPCMessage =>\n JSONRPCMessageSchema.safeParse(value).success;\n\n/**\n * Configuration options for reconnection behavior, mirroring BrowserReconnectionOptions\n */\nexport interface ExtensionReconnectionOptions {\n maxReconnectionDelay: number;\n initialReconnectionDelay: number;\n reconnectionDelayGrowFactor: number;\n maxRetries: number;\n}\n\nconst DEFAULT_EXTENSION_RECONNECTION_OPTIONS: ExtensionReconnectionOptions = {\n initialReconnectionDelay: 1000,\n maxReconnectionDelay: 30000,\n reconnectionDelayGrowFactor: 1.5,\n maxRetries: 2,\n};\n\n/**\n * Configuration options for the ExtensionClientTransport\n */\nexport interface ExtensionClientTransportOptions {\n clientInstanceId?: string;\n reconnectionOptions?: ExtensionReconnectionOptions;\n connectionTimeout?: number;\n}\n\nexport class ExtensionClientTransport implements Transport {\n onclose?: () => void;\n onerror?: (err: Error) => void;\n onmessage?: (message: JSONRPCMessage, extra?: { authInfo?: any }) => void;\n\n public isConnected = false;\n public sessionId?: string;\n public lastEventId?: EventId;\n public serverInstanceId?: string;\n public hasEventStore: boolean = false;\n public streamId?: string;\n\n private clientId: string;\n private bridge: ReturnType<typeof createUIBridge>;\n\n private _reconnectionOptions: ExtensionReconnectionOptions;\n private _connectionTimeout: number;\n private _abortController?: AbortController;\n private _connectionPromise?: {\n resolve: () => void;\n reject: (error: Error) => void;\n };\n private _reconnectAttempt: number = 0;\n private _startPromise?: Promise<void>;\n\n constructor(options?: ExtensionClientTransportOptions & { port?: chrome.runtime.Port }) {\n this.clientId =\n options?.clientInstanceId ||\n (crypto.randomUUID?.() ?? `ext-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);\n\n this._reconnectionOptions =\n options?.reconnectionOptions ?? DEFAULT_EXTENSION_RECONNECTION_OPTIONS;\n this._connectionTimeout = options?.connectionTimeout ?? 30000;\n this.bridge = createUIBridge(options?.port);\n\n // Set up the message handler once for the lifetime of this transport\n this._setupMessageHandler();\n }\n\n private _setupMessageHandler(): void {\n this.bridge.onMessage((resp: BridgeResponse) => {\n console.log(\n `ExtensionClientTransport: Received message for client ${resp.clientId}`,\n 'Expected client:',\n this.clientId,\n 'Match:',\n resp.clientId === this.clientId,\n 'Message type:',\n resp.msg && 'type' in resp.msg ? resp.msg.type : 'unknown'\n );\n\n // Only process messages for our client ID\n if (resp.clientId !== this.clientId) {\n console.log(\n `ExtensionClientTransport: Ignoring message for different client. Expected ${this.clientId}, got ${resp.clientId}`\n );\n return;\n }\n\n const data: PageBridgeMessageType = resp.msg;\n try {\n // HANDLE THE SERVER-SIDE DISCONNECT NOTIFICATION\n if ('type' in data && data.type === 'mcp-server-disconnected') {\n console.warn(\n `ExtensionClientTransport: Server for client ${this.clientId} disconnected unexpectedly.`\n );\n\n // If we thought we were connected, trigger the full close/reconnect cycle.\n if (this.isConnected) {\n this.isConnected = false; // Immediately update state\n const error = new Error('The server-side transport has disconnected.');\n\n // Re-use the existing connection error handler. It contains the logic\n // to attempt reconnection based on your options.\n this._handleConnectionError(error, this.lastEventId);\n }\n return;\n }\n\n if ('type' in data && data.type === 'mcp-server-info') {\n const serverInfo = data as MCPServerInfoMessage;\n console.log(\n `ExtensionClientTransport: Received server info for client ${this.clientId}`,\n serverInfo\n );\n\n // Only process if we're expecting a handshake (have a connection promise)\n if (this._connectionPromise) {\n this.sessionId = serverInfo.serverSessionId;\n this.serverInstanceId = serverInfo.serverInstanceId;\n this.hasEventStore = serverInfo.hasEventStore || false;\n this.streamId = serverInfo.streamId;\n this.isConnected = true;\n this._reconnectAttempt = 0;\n const promise = this._connectionPromise;\n this._connectionPromise = undefined;\n promise.resolve();\n } else {\n console.warn(\n `ExtensionClientTransport: Received server info but no connection promise pending`\n );\n }\n return;\n }\n\n // Only process other messages if we're connected\n if (!this.isConnected) {\n console.warn('ExtensionClientTransport: Received message while not connected', data);\n return;\n }\n\n // Handle messages after connection established\n if ('type' in data && (data.type === 'mcp-replay-event' || data.type === 'mcp-event')) {\n const eventMsg = data as MCPEventMessage | MCPReplayEventMessage;\n this.lastEventId = eventMsg.eventId;\n if (isJSONRPCMessage(eventMsg.message)) {\n this.onmessage?.(eventMsg.message);\n } else {\n const message = JSONRPCMessageSchema.parse(eventMsg.message);\n this.onmessage?.(message);\n }\n } else if (isJSONRPCMessage(data)) {\n // Check if it's a direct JSONRPCMessage\n this.onmessage?.(data);\n } else {\n console.warn('ExtensionClientTransport received unknown message type:', data);\n }\n } catch (err) {\n const error = err as Error;\n console.error(\n 'Error processing message in ExtensionClientTransport:',\n error,\n 'Data:',\n data\n );\n this.onerror?.(error);\n }\n });\n }\n\n async start(): Promise<void> {\n if (this._startPromise) {\n console.warn(\n 'ExtensionClientTransport already started, returning existing connection promise'\n );\n return this._startPromise;\n }\n\n if (this._abortController) {\n console.warn('ExtensionClientTransport already started!');\n // If we have an abort controller but no start promise, we're in an inconsistent state\n // Return a resolved promise if connected, otherwise create a new connection\n if (this.isConnected) {\n return Promise.resolve();\n }\n }\n\n this._abortController = new AbortController();\n this._startPromise = this._connectWithRetry().finally(() => {\n // Clear the start promise once connection attempt completes (success or failure)\n this._startPromise = undefined;\n });\n\n return this._startPromise;\n }\n\n private async _connectWithRetry(resumptionToken?: EventId): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this._connectionPromise = { resolve, reject };\n let handshakeTimer: ReturnType<typeof setTimeout>;\n\n const signal = this._abortController?.signal;\n if (signal?.aborted) {\n return reject(new Error('Connection aborted'));\n }\n\n console.log(\n `ExtensionClientTransport: Starting connection for client ${this.clientId}`,\n resumptionToken ? `with resumption token ${resumptionToken}` : 'without resumption token'\n );\n\n // Message handler is already set up in constructor\n\n const connectOptions: MCPConnectOptions | undefined = resumptionToken\n ? { resumeFrom: resumptionToken }\n : undefined;\n\n console.log(\n `ExtensionClientTransport: Sending connect command for client ${this.clientId}`,\n connectOptions\n );\n this.bridge.connect(this.clientId, connectOptions);\n\n handshakeTimer = setTimeout(() => {\n if (!this.isConnected && this._connectionPromise) {\n const error = new Error(\n `ExtensionClientTransport: Server handshake timeout for client ${this.clientId}`\n );\n this._handleConnectionError(error, resumptionToken);\n }\n }, this._connectionTimeout);\n\n // Store handshake timer reference so it can be cleared when connection succeeds\n const originalResolve = this._connectionPromise.resolve;\n this._connectionPromise.resolve = () => {\n if (handshakeTimer) clearTimeout(handshakeTimer);\n originalResolve();\n };\n\n signal?.addEventListener('abort', () => {\n if (handshakeTimer) clearTimeout(handshakeTimer);\n // If connectionPromise still exists, it means we haven't resolved/rejected it yet.\n if (this._connectionPromise) {\n this._connectionPromise.reject(new Error('Connection aborted during handshake'));\n this._connectionPromise = undefined;\n }\n });\n });\n }\n\n private _handleConnectionError(error: Error, resumptionToken?: EventId): void {\n this.onerror?.(error);\n this.isConnected = false; // Ensure disconnected state\n\n if (this._connectionPromise) {\n this._connectionPromise.reject(error);\n this._connectionPromise = undefined;\n }\n\n // Attempt reconnection if appropriate (not aborted and lastEventId exists for resumption)\n const shouldRetry =\n this._abortController &&\n !this._abortController.signal.aborted &&\n (resumptionToken || this.lastEventId) && // Need a token to resume\n this._reconnectionOptions.maxRetries > 0 &&\n this._reconnectAttempt < this._reconnectionOptions.maxRetries;\n\n if (shouldRetry) {\n this._scheduleReconnection(resumptionToken || this.lastEventId!);\n } else {\n // If no retry, call onclose if it was previously connected or trying to connect\n // This prevents calling onclose if start() was never called or already closed.\n if (this._abortController) {\n // Check if connection process was initiated\n this.onclose?.();\n // Clean up abort controller as we are fully stopping\n this._abortController = undefined;\n }\n }\n }\n\n private _getNextReconnectionDelay(attempt: number): number {\n const { initialReconnectionDelay, maxReconnectionDelay, reconnectionDelayGrowFactor } =\n this._reconnectionOptions;\n return Math.min(\n initialReconnectionDelay * Math.pow(reconnectionDelayGrowFactor, attempt),\n maxReconnectionDelay\n );\n }\n\n private _scheduleReconnection(tokenToResume: EventId): void {\n const delay = this._getNextReconnectionDelay(this._reconnectAttempt);\n this._reconnectAttempt++;\n\n console.log(\n `ExtensionClientTransport: Scheduling reconnection attempt ${this._reconnectAttempt} in ${delay}ms`\n );\n\n setTimeout(() => {\n if (this._abortController?.signal.aborted) {\n console.log('ExtensionClientTransport: Reconnection aborted.');\n return;\n }\n console.log(\n `ExtensionClientTransport: Attempting reconnection (attempt ${this._reconnectAttempt})`\n );\n this._connectWithRetry(tokenToResume).catch((err) => {\n // Error during a scheduled reconnection attempt is handled by _handleConnectionError within that attempt.\n // We log it here for visibility, but _handleConnectionError will decide on further retries or final close.\n console.error(`ExtensionClientTransport: Scheduled reconnection attempt failed:`, err);\n // If _handleConnectionError doesn't schedule another retry, it will call onclose.\n });\n }, delay);\n }\n\n async send(message: JSONRPCMessage, _?: TransportSendOptions): Promise<void> {\n // options?.resumptionToken and options?.onresumptiontoken are not directly applicable here\n // as the extension bridge manages its own event stream concept via lastEventId internally.\n\n // If there's a start promise pending, wait for it\n if (this._startPromise) {\n console.log('ExtensionClientTransport: Waiting for initial connection before send.');\n try {\n await this._startPromise;\n } catch (err) {\n const error = new Error(\n `ExtensionClientTransport: Failed to establish initial connection: ${err instanceof Error ? err.message : String(err)}`\n );\n this.onerror?.(error);\n throw error;\n }\n }\n\n if (!this.isConnected) {\n const canAttemptReconnect =\n this._reconnectionOptions.maxRetries > 0 &&\n this.lastEventId &&\n this._abortController &&\n !this._abortController.signal.aborted;\n if (canAttemptReconnect) {\n console.log(\n 'ExtensionClientTransport: Not connected. Attempting auto-reconnect before send.'\n );\n try {\n await this._connectWithRetry(this.lastEventId);\n } catch (err) {\n const reconErr = new Error(\n `ExtensionClientTransport: Failed to auto-reconnect before send: ${err instanceof Error ? err.message : String(err)}`\n );\n this.onerror?.(reconErr);\n throw reconErr; // Propagate error if reconnection fails\n }\n if (!this.isConnected) {\n throw new Error(\n 'ExtensionClientTransport: Not connected after attempting auto-reconnection.'\n );\n }\n } else {\n throw new Error('ExtensionClientTransport: Not connected and cannot auto-reconnect.');\n }\n }\n this.bridge.send(this.clientId, message);\n }\n\n async close(): Promise<void> {\n if (this._abortController) {\n this._abortController.abort();\n this._abortController = undefined; // Clear it as we are now closed\n }\n\n if (this._connectionPromise) {\n this._connectionPromise.reject(\n new Error('ExtensionClientTransport: Transport closed by client.')\n );\n this._connectionPromise = undefined;\n }\n\n // Clear any pending start promise\n this._startPromise = undefined;\n\n // Future: If bridge supported explicit disconnect message:\n // if (this.isConnected) { // Or even if not, to clean up server-side if client ID is known\n // this.bridge.disconnect(this.clientId); // This would need to be added to UIBridge and handled by background\n // }\n\n this.isConnected = false;\n // Only call onclose if it hasn't been called by _handleConnectionError already\n // However, a direct call to close() should always trigger onclose if not already closed.\n // The _abortController being undefined (set by _handleConnectionError on final failure or here on direct close)\n // can be a guard. If _handleConnectionError already cleaned up, onclose was called.\n // For simplicity now: always call onclose, assuming it handles multiple calls gracefully or is only set once.\n this.onclose?.();\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/TabClientTransport.ts","../src/TabServerTransport.ts","../src/ExtensionClientTransport.ts","../src/ExtensionServerTransport.ts","../src/WebsocketClientTransport.ts","../src/WebsocketServerTransport.ts","../src/BrowserWebSocketClientTransport.ts"],"names":["TabClientTransport","options","event","message","JSONRPCMessageSchema","error","TabServerTransport","ExtensionClientTransport","resolve","reject","mcpMessage","_options","ExtensionServerTransport","port","SUBPROTOCOL","WebSocketClientTransport","url","ws","data","dataStr","WebSocketServerTransport","socket","parsedData","connectionId","actualMessage","messageToSend","BrowserWebSocketClientTransport","_event"],"mappings":"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","file":"index.js","sourcesContent":["import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { JSONRPCMessage, JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';\n\nexport interface TabClientTransportOptions {\n targetOrigin: string; // Required for security\n channelId?: string; // Optional channel name\n}\n\nexport class TabClientTransport implements Transport {\n private _started = false;\n private _targetOrigin: string;\n private _channelId: string;\n private _messageHandler?: (event: MessageEvent) => void;\n\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n constructor(options: TabClientTransportOptions) {\n if (!options.targetOrigin) {\n throw new Error('targetOrigin must be explicitly set for security');\n }\n this._targetOrigin = options.targetOrigin;\n this._channelId = options.channelId || 'mcp-default';\n }\n\n async start(): Promise<void> {\n if (this._started) {\n throw new Error('Transport already started');\n }\n\n this._messageHandler = (event: MessageEvent) => {\n // Security: validate origin\n if (event.origin !== this._targetOrigin) {\n return;\n }\n\n // Validate message structure\n if (event.data?.channel !== this._channelId || event.data?.type !== 'mcp') {\n return;\n }\n\n // Only process server-to-client messages to avoid processing own messages\n if (event.data?.direction !== 'server-to-client') {\n return;\n }\n\n try {\n const message = JSONRPCMessageSchema.parse(event.data.payload);\n this.onmessage?.(message);\n } catch (error) {\n this.onerror?.(new Error(`Invalid message: ${error}`));\n }\n };\n\n window.addEventListener('message', this._messageHandler);\n this._started = true;\n }\n\n async send(message: JSONRPCMessage): Promise<void> {\n if (!this._started) {\n throw new Error('Transport not started');\n }\n\n window.postMessage(\n {\n channel: this._channelId,\n type: 'mcp',\n direction: 'client-to-server', // Mark as client-to-server message\n payload: message,\n },\n this._targetOrigin\n );\n }\n\n async close(): Promise<void> {\n if (this._messageHandler) {\n window.removeEventListener('message', this._messageHandler);\n }\n this._started = false;\n this.onclose?.();\n }\n}\n","import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { JSONRPCMessage, JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';\n\nexport interface TabServerTransportOptions {\n allowedOrigins: string[]; // Required for security\n channelId?: string; // Optional channel name\n}\n\nexport class TabServerTransport implements Transport {\n private _started = false;\n private _allowedOrigins: string[] | '*';\n private _channelId: string;\n private _messageHandler?: (event: MessageEvent) => void;\n private _clientOrigin?: string;\n\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n constructor(options: TabServerTransportOptions) {\n if (!options.allowedOrigins || options.allowedOrigins.length === 0) {\n throw new Error('At least one allowed origin must be specified');\n }\n this._allowedOrigins = options.allowedOrigins;\n this._channelId = options.channelId || 'mcp-default';\n }\n\n async start(): Promise<void> {\n if (this._started) {\n throw new Error('Transport already started');\n }\n\n this._messageHandler = (event: MessageEvent) => {\n console.log({ event });\n // Security: validate origin\n if (!this._allowedOrigins.includes(event.origin) && !this._allowedOrigins.includes('*')) {\n return;\n }\n\n // Validate message structure\n if (event.data?.channel !== this._channelId || event.data?.type !== 'mcp') {\n return;\n }\n\n // Only process client-to-server messages to avoid processing own messages\n if (event.data?.direction !== 'client-to-server') {\n return;\n }\n\n // Store client origin for responses\n this._clientOrigin = event.origin;\n\n try {\n const message = JSONRPCMessageSchema.parse(event.data.payload);\n this.onmessage?.(message);\n } catch (error) {\n this.onerror?.(new Error(`Invalid message: ${error}`));\n }\n };\n\n window.addEventListener('message', this._messageHandler);\n this._started = true;\n }\n\n async send(message: JSONRPCMessage): Promise<void> {\n if (!this._started) {\n throw new Error('Transport not started');\n }\n\n if (!this._clientOrigin) {\n throw new Error('No client connected');\n }\n\n window.postMessage(\n {\n channel: this._channelId,\n type: 'mcp',\n direction: 'server-to-client', // Mark as server-to-client message\n payload: message,\n },\n this._clientOrigin\n );\n }\n\n async close(): Promise<void> {\n if (this._messageHandler) {\n window.removeEventListener('message', this._messageHandler);\n }\n this._started = false;\n this.onclose?.();\n }\n}\n","import { Transport, TransportSendOptions } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { JSONRPCMessage, JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';\n\n/**\n * Configuration options for ExtensionClientTransport\n */\nexport interface ExtensionClientTransportOptions {\n /**\n * The extension ID to connect to (optional for same-extension connections)\n */\n extensionId?: string;\n\n /**\n * Port name for the connection\n * Default: 'mcp'\n */\n portName?: string;\n}\n\n/**\n * Client transport for Chrome extensions using Port-based messaging.\n * This transport can be used in content scripts, popup scripts, or sidepanel scripts\n * to connect to a server running in the background service worker.\n */\nexport class ExtensionClientTransport implements Transport {\n private _port?: chrome.runtime.Port;\n private _extensionId?: string;\n private _portName: string;\n private _messageHandler?: (message: any) => void;\n private _disconnectHandler?: () => void;\n\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n constructor(options: ExtensionClientTransportOptions = {}) {\n this._extensionId = options.extensionId;\n this._portName = options.portName || 'mcp';\n }\n\n /**\n * Starts the transport by connecting to the extension port\n */\n async start(): Promise<void> {\n if (this._port) {\n throw new Error(\n 'ExtensionClientTransport already started! If using Client class, note that connect() calls start() automatically.'\n );\n }\n\n return new Promise((resolve, reject) => {\n if (!chrome?.runtime?.connect) {\n reject(\n new Error(\n 'Chrome runtime API not available. This transport must be used in a Chrome extension context.'\n )\n );\n return;\n }\n\n try {\n // Connect to the extension\n if (this._extensionId) {\n this._port = chrome.runtime.connect(this._extensionId, { name: this._portName });\n } else {\n this._port = chrome.runtime.connect({ name: this._portName });\n }\n\n // Set up message handler\n this._messageHandler = (message: any) => {\n try {\n const mcpMessage = JSONRPCMessageSchema.parse(message);\n this.onmessage?.(mcpMessage);\n } catch (error) {\n this.onerror?.(new Error(`Failed to parse message: ${error}`));\n }\n };\n\n // Set up disconnect handler\n this._disconnectHandler = () => {\n this._cleanup();\n this.onclose?.();\n };\n\n this._port.onMessage.addListener(this._messageHandler);\n this._port.onDisconnect.addListener(this._disconnectHandler);\n\n // Check for immediate connection errors\n const error = chrome.runtime.lastError;\n if (error) {\n this._cleanup();\n reject(new Error(`Connection failed: ${error.message}`));\n return;\n }\n\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * Sends a message to the server\n */\n async send(message: JSONRPCMessage, _options?: TransportSendOptions): Promise<void> {\n if (!this._port) {\n throw new Error('Not connected');\n }\n\n try {\n this._port.postMessage(message);\n } catch (error) {\n throw new Error(`Failed to send message: ${error}`);\n }\n }\n\n /**\n * Closes the transport\n */\n async close(): Promise<void> {\n if (this._port) {\n try {\n this._port.disconnect();\n } catch (error) {\n // Port might already be disconnected\n }\n }\n\n this._cleanup();\n this.onclose?.();\n }\n\n /**\n * Cleans up event listeners and references\n */\n private _cleanup(): void {\n if (this._port) {\n if (this._messageHandler) {\n this._port.onMessage.removeListener(this._messageHandler);\n }\n if (this._disconnectHandler) {\n this._port.onDisconnect.removeListener(this._disconnectHandler);\n }\n }\n this._port = undefined;\n }\n}\n","import { Transport, TransportSendOptions } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { JSONRPCMessage, JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';\n\n/**\n * Server transport for Chrome extensions using Port-based messaging.\n * This transport handles a single client connection through Chrome's port messaging API.\n * It should be used in the extension's background service worker.\n */\nexport class ExtensionServerTransport implements Transport {\n private _port: chrome.runtime.Port;\n private _started = false;\n private _messageHandler?: (message: any, port: chrome.runtime.Port) => void;\n private _disconnectHandler?: (port: chrome.runtime.Port) => void;\n\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n constructor(port: chrome.runtime.Port) {\n this._port = port;\n }\n\n /**\n * Starts the transport and begins handling messages\n */\n async start(): Promise<void> {\n if (this._started) {\n throw new Error(\n 'ExtensionServerTransport already started! If using Server class, note that connect() calls start() automatically.'\n );\n }\n\n if (!this._port) {\n throw new Error('Port not available');\n }\n\n this._started = true;\n\n // Set up message handler\n this._messageHandler = (message: any) => {\n try {\n const mcpMessage = JSONRPCMessageSchema.parse(message);\n this.onmessage?.(mcpMessage);\n } catch (error) {\n this.onerror?.(new Error(`Failed to parse message: ${error}`));\n }\n };\n\n // Set up disconnect handler\n this._disconnectHandler = () => {\n this._cleanup();\n this.onclose?.();\n };\n\n this._port.onMessage.addListener(this._messageHandler);\n this._port.onDisconnect.addListener(this._disconnectHandler);\n }\n\n /**\n * Sends a message to the client\n */\n async send(message: JSONRPCMessage, _options?: TransportSendOptions): Promise<void> {\n if (!this._started) {\n throw new Error('Transport not started');\n }\n\n if (!this._port) {\n throw new Error('Not connected to client');\n }\n\n try {\n this._port.postMessage(message);\n } catch (error) {\n throw new Error(`Failed to send message: ${error}`);\n }\n }\n\n /**\n * Closes the transport\n */\n async close(): Promise<void> {\n this._started = false;\n\n if (this._port) {\n try {\n this._port.disconnect();\n } catch (error) {\n // Port might already be disconnected\n }\n }\n\n this._cleanup();\n this.onclose?.();\n }\n\n /**\n * Cleans up event listeners and references\n */\n private _cleanup(): void {\n if (this._port) {\n if (this._messageHandler) {\n this._port.onMessage.removeListener(this._messageHandler);\n }\n if (this._disconnectHandler) {\n this._port.onDisconnect.removeListener(this._disconnectHandler);\n }\n }\n }\n}\n","import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { JSONRPCMessage, JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';\n\nconst SUBPROTOCOL = 'mcp';\n\n/**\n * Client transport for WebSocket: this will connect to a server over the WebSocket protocol.\n * This transport is Node.js specific and requires the 'ws' package to be installed.\n */\nexport class WebSocketClientTransport implements Transport {\n private _socket?: any; // WebSocket type from 'ws' package\n private _url: URL;\n private _WebSocket?: typeof import('ws').WebSocket;\n\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n constructor(url: URL) {\n this._url = url;\n }\n\n async start(): Promise<void> {\n if (this._socket) {\n throw new Error(\n 'WebSocketClientTransport already started! If using Client class, note that connect() calls start() automatically.'\n );\n }\n\n // Dynamically import the WebSocket class from 'ws' package\n if (!this._WebSocket) {\n try {\n const ws = await import('ws');\n this._WebSocket = ws.WebSocket;\n } catch (error) {\n throw new Error(\"Failed to import 'ws' package. Please install it with: npm install ws\");\n }\n }\n\n return new Promise((resolve, reject) => {\n // Create WebSocket instance with Node.js specific options\n this._socket = new this._WebSocket!(this._url.toString(), {\n perMessageDeflate: false,\n // Add the subprotocol in the options\n ...(SUBPROTOCOL ? { protocol: SUBPROTOCOL } : {}),\n });\n\n // Node.js WebSocket error event handler\n this._socket.on('error', (error: Error) => {\n reject(error);\n this.onerror?.(error);\n });\n\n // Node.js WebSocket open event handler\n this._socket.on('open', () => {\n resolve();\n });\n\n // Node.js WebSocket close event handler\n this._socket.on('close', () => {\n this.onclose?.();\n });\n\n // Node.js WebSocket message event handler\n this._socket.on('message', (data: Buffer | ArrayBuffer | Buffer[]) => {\n let message: JSONRPCMessage;\n try {\n // Convert Buffer to string before parsing\n const dataStr = data instanceof Buffer ? data.toString('utf-8') : data.toString();\n message = JSONRPCMessageSchema.parse(JSON.parse(dataStr));\n } catch (error) {\n this.onerror?.(error as Error);\n return;\n }\n this.onmessage?.(message);\n });\n });\n }\n\n async close(): Promise<void> {\n if (this._socket && this._WebSocket) {\n // Check the readyState before closing\n if (this._socket.readyState === this._WebSocket.OPEN) {\n this._socket.close();\n }\n }\n }\n\n async send(message: JSONRPCMessage): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this._socket || !this._WebSocket) {\n reject(new Error('Not connected'));\n return;\n }\n\n // Check if the socket is open before sending\n if (this._socket.readyState !== this._WebSocket.OPEN) {\n reject(new Error('WebSocket is not open'));\n return;\n }\n\n // In Node.js, send accepts a callback for error handling\n this._socket.send(JSON.stringify(message), (error?: Error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n }\n}\n","import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { JSONRPCMessage, JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';\n\n/**\n * Server transport for WebSocket: this will accept connections from MCP clients over WebSocket protocol.\n * Designed to work in browser extension environments.\n */\nexport class WebSocketServerTransport implements Transport {\n private _socket?: WebSocket;\n private _server?: any; // For environments that support WebSocketServer\n private _started = false;\n private _connectionId?: string;\n\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n constructor(\n private _options: {\n /**\n * For browser extensions: provide an existing WebSocket connection\n */\n socket?: WebSocket;\n /**\n * For Node.js: provide port to create WebSocketServer\n */\n port?: number;\n }\n ) {}\n\n /**\n * Starts the transport. In browser extension context, this validates the socket.\n */\n async start(): Promise<void> {\n if (this._started) {\n throw new Error(\n 'WebSocketServerTransport already started! If using Server class, note that connect() calls start() automatically.'\n );\n }\n this._started = true;\n\n if (this._options.socket) {\n this._socket = this._options.socket;\n this.setupSocketHandlers(this._socket);\n } else {\n throw new Error('WebSocketServerTransport requires either a socket ');\n }\n }\n\n private setupSocketHandlers(socket: WebSocket): void {\n socket.onmessage = (event: MessageEvent) => {\n let message: JSONRPCMessage;\n try {\n const data = typeof event.data === 'string' ? event.data : event.data.toString();\n const parsedData = JSON.parse(data);\n\n // Handle bridge protocol - extract connectionId if present\n if (parsedData.connectionId) {\n this._connectionId = parsedData.connectionId;\n const { connectionId, ...actualMessage } = parsedData;\n message = JSONRPCMessageSchema.parse(actualMessage);\n } else {\n message = JSONRPCMessageSchema.parse(parsedData);\n }\n } catch (error) {\n this.onerror?.(error as Error);\n return;\n }\n this.onmessage?.(message);\n };\n\n socket.onerror = (event: Event) => {\n const error = new Error(`WebSocket error: ${JSON.stringify(event)}`);\n this.onerror?.(error);\n };\n\n socket.onclose = () => {\n this._socket = undefined;\n this.onclose?.();\n };\n }\n\n async close(): Promise<void> {\n if (this._socket) {\n this._socket.close();\n this._socket = undefined;\n }\n\n if (this._server) {\n return new Promise((resolve) => {\n this._server.close(() => {\n this._server = undefined;\n resolve();\n });\n });\n }\n }\n\n send(message: JSONRPCMessage): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this._socket || this._socket.readyState !== WebSocket.OPEN) {\n reject(new Error('No active WebSocket connection'));\n return;\n }\n\n try {\n // If we have a connectionId from the bridge, include it in the response\n const messageToSend = this._connectionId\n ? { ...message, connectionId: this._connectionId }\n : message;\n\n this._socket.send(JSON.stringify(messageToSend));\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * Get the current WebSocket connection (if any)\n */\n get socket(): WebSocket | undefined {\n return this._socket;\n }\n\n /**\n * Check if transport has an active connection\n */\n get isConnected(): boolean {\n return this._socket?.readyState === WebSocket.OPEN;\n }\n}\n","import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { JSONRPCMessage, JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';\n\n/**\n * Browser-compatible WebSocket client transport for connecting from browser extensions to a bridge server.\n * This transport uses the native browser WebSocket API and doesn't require any Node.js dependencies.\n */\nexport class BrowserWebSocketClientTransport implements Transport {\n private _socket?: WebSocket;\n private _url: string;\n private _connectionId?: string;\n\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n constructor(url: string | URL) {\n this._url = url.toString();\n }\n\n async start(): Promise<void> {\n if (this._socket) {\n throw new Error(\n 'BrowserWebSocketClientTransport already started! If using Client class, note that connect() calls start() automatically.'\n );\n }\n\n return new Promise((resolve, reject) => {\n try {\n // Create WebSocket with browser API\n this._socket = new WebSocket(this._url);\n\n this._socket.onopen = () => {\n resolve();\n };\n\n this._socket.onerror = (_event) => {\n const error = new Error(`WebSocket connection error`);\n reject(error);\n this.onerror?.(error);\n };\n\n this._socket.onclose = () => {\n this._socket = undefined;\n this._connectionId = undefined;\n this.onclose?.();\n };\n\n this._socket.onmessage = (event: MessageEvent) => {\n let data: any;\n try {\n data = JSON.parse(event.data);\n\n // Handle bridge-specific messages\n if (data.connectionId && !this._connectionId) {\n // Store connectionId for future messages\n this._connectionId = data.connectionId;\n }\n\n // Extract the actual message\n if (data.connectionId) {\n const { connectionId, ...message } = data;\n data = message;\n }\n\n const message = JSONRPCMessageSchema.parse(data);\n this.onmessage?.(message);\n } catch (error) {\n this.onerror?.(error as Error);\n }\n };\n } catch (error) {\n reject(error);\n }\n });\n }\n\n async close(): Promise<void> {\n if (this._socket && this._socket.readyState === WebSocket.OPEN) {\n this._socket.close();\n }\n }\n\n async send(message: JSONRPCMessage): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this._socket || this._socket.readyState !== WebSocket.OPEN) {\n reject(new Error('WebSocket is not connected'));\n return;\n }\n\n try {\n // If we have a connectionId from the bridge, include it\n const messageToSend = this._connectionId\n ? { ...message, connectionId: this._connectionId }\n : message;\n\n this._socket.send(JSON.stringify(messageToSend));\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * Check if transport is connected\n */\n get isConnected(): boolean {\n return this._socket?.readyState === WebSocket.OPEN;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@mcp-b/transports",
3
- "version": "0.0.1",
3
+ "version": "0.1.2",
4
4
  "description": "Transports for the in browser transport protocols",
5
5
  "license": "MIT",
6
- "author": "mcp-b Team",
6
+ "author": "Alex Nahas",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/alxnahas/mcp-b.git",
9
+ "url": "git+https://github.com/miguelspizza/mcp-b.git",
10
10
  "directory": "packages/mcp-b"
11
11
  },
12
- "homepage": "https://github.com/alxnahas/mcp-b#readme",
12
+ "homepage": "https://github.com/miguelspizza/mcp-b#readme",
13
13
  "bugs": {
14
- "url": "https://github.com/alxnahas/mcp-b/issues"
14
+ "url": "https://github.com/miguelspizza/mcp-b/issues"
15
15
  },
16
16
  "keywords": [
17
17
  "mcp",
@@ -33,25 +33,43 @@
33
33
  "files": [
34
34
  "dist"
35
35
  ],
36
- "scripts": {
37
- "build": "tsup",
38
- "dev": "tsup --watch",
39
- "typecheck": "tsc --noEmit",
40
- "clean": "rm -rf dist .turbo"
41
- },
42
- "peerDependencies": {},
43
36
  "dependencies": {
44
- "@modelcontextprotocol/sdk": "^1.12.1"
37
+ "@modelcontextprotocol/sdk": "^1.12.1",
38
+ "@types/cheerio": "^1.0.0",
39
+ "cheerio": "^1.1.0",
40
+ "zod": "^3.24.1"
41
+ },
42
+ "peerDependencies": {
43
+ "@anthropic-ai/sdk": "^0.54.0",
44
+ "ws": "^8.0.0"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "ws": {
48
+ "optional": true
49
+ },
50
+ "@anthropic-ai/sdk": {
51
+ "optional": true
52
+ }
45
53
  },
46
54
  "devDependencies": {
47
- "@types/react": "catalog:",
48
- "@types/node": "catalog:",
49
- "tsup": "catalog:",
50
- "typescript": "catalog:",
51
- "@types/chrome": "^0.0.326"
55
+ "@types/chrome": "^0.0.326",
56
+ "@types/node": "^22.10.3",
57
+ "@types/ws": "^8.5.0",
58
+ "tsup": "^8.3.5",
59
+ "typescript": "^5.8.3"
52
60
  },
53
61
  "publishConfig": {
54
62
  "access": "public",
55
63
  "registry": "https://registry.npmjs.org/"
64
+ },
65
+ "scripts": {
66
+ "build": "tsup",
67
+ "typecheck": "tsc --noEmit",
68
+ "clean": "rm -rf dist .turbo",
69
+ "publish:npm": "pnpm publish --access public --no-git-checks",
70
+ "publish:dry": "pnpm publish --access public --no-git-checks --dry-run",
71
+ "version:patch": "pnpm version patch --no-git-tag-version",
72
+ "version:minor": "pnpm version minor --no-git-tag-version",
73
+ "version:major": "pnpm version major --no-git-tag-version"
56
74
  }
57
- }
75
+ }