@mcp-b/transports 0.1.0 → 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.d.ts +23 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -143,6 +143,7 @@ declare class WebSocketServerTransport implements Transport {
|
|
|
143
143
|
private _socket?;
|
|
144
144
|
private _server?;
|
|
145
145
|
private _started;
|
|
146
|
+
private _connectionId?;
|
|
146
147
|
onclose?: () => void;
|
|
147
148
|
onerror?: (error: Error) => void;
|
|
148
149
|
onmessage?: (message: JSONRPCMessage) => void;
|
|
@@ -173,6 +174,27 @@ declare class WebSocketServerTransport implements Transport {
|
|
|
173
174
|
get isConnected(): boolean;
|
|
174
175
|
}
|
|
175
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Browser-compatible WebSocket client transport for connecting from browser extensions to a bridge server.
|
|
179
|
+
* This transport uses the native browser WebSocket API and doesn't require any Node.js dependencies.
|
|
180
|
+
*/
|
|
181
|
+
declare class BrowserWebSocketClientTransport implements Transport {
|
|
182
|
+
private _socket?;
|
|
183
|
+
private _url;
|
|
184
|
+
private _connectionId?;
|
|
185
|
+
onclose?: () => void;
|
|
186
|
+
onerror?: (error: Error) => void;
|
|
187
|
+
onmessage?: (message: JSONRPCMessage) => void;
|
|
188
|
+
constructor(url: string | URL);
|
|
189
|
+
start(): Promise<void>;
|
|
190
|
+
close(): Promise<void>;
|
|
191
|
+
send(message: JSONRPCMessage): Promise<void>;
|
|
192
|
+
/**
|
|
193
|
+
* Check if transport is connected
|
|
194
|
+
*/
|
|
195
|
+
get isConnected(): boolean;
|
|
196
|
+
}
|
|
197
|
+
|
|
176
198
|
/**
|
|
177
199
|
* Unique identifier for an event in the event store
|
|
178
200
|
*/
|
|
@@ -300,4 +322,4 @@ interface StoredEvent {
|
|
|
300
322
|
clientId: string;
|
|
301
323
|
}
|
|
302
324
|
|
|
303
|
-
export { type EventId, ExtensionClientTransport, type ExtensionClientTransportOptions, ExtensionServerTransport, type MCPBrowserInterface, type MCPConnectOptions, type MCPEventMessage, type MCPEventStore, type MCPReplayEventMessage, type MCPServerInfo, type MCPServerInfoMessage, type MCPWindow, type StoredEvent, type StreamId, TabClientTransport, type TabClientTransportOptions, TabServerTransport, type TabServerTransportOptions, WebSocketClientTransport, WebSocketServerTransport };
|
|
325
|
+
export { BrowserWebSocketClientTransport, type EventId, ExtensionClientTransport, type ExtensionClientTransportOptions, ExtensionServerTransport, type MCPBrowserInterface, type MCPConnectOptions, type MCPEventMessage, type MCPEventStore, type MCPReplayEventMessage, type MCPServerInfo, type MCPServerInfoMessage, type MCPWindow, type StoredEvent, type StreamId, TabClientTransport, type TabClientTransportOptions, TabServerTransport, type TabServerTransportOptions, WebSocketClientTransport, WebSocketServerTransport };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {JSONRPCMessageSchema}from'@modelcontextprotocol/sdk/types.js';var
|
|
1
|
+
import {JSONRPCMessageSchema}from'@modelcontextprotocol/sdk/types.js';var a=class{_started=false;_targetOrigin;_channelId;_messageHandler;onclose;onerror;onmessage;constructor(e){if(!e.targetOrigin)throw new Error("targetOrigin must be explicitly set for security");this._targetOrigin=e.targetOrigin,this._channelId=e.channelId||"mcp-default";}async start(){if(this._started)throw new Error("Transport already started");this._messageHandler=e=>{if(e.origin===this._targetOrigin&&!(e.data?.channel!==this._channelId||e.data?.type!=="mcp")&&e.data?.direction==="server-to-client")try{let r=JSONRPCMessageSchema.parse(e.data.payload);this.onmessage?.(r);}catch(r){this.onerror?.(new Error(`Invalid message: ${r}`));}},window.addEventListener("message",this._messageHandler),this._started=true;}async send(e){if(!this._started)throw new Error("Transport not started");window.postMessage({channel:this._channelId,type:"mcp",direction:"client-to-server",payload:e},this._targetOrigin);}async close(){this._messageHandler&&window.removeEventListener("message",this._messageHandler),this._started=false,this.onclose?.();}};var c=class{_started=false;_allowedOrigins;_channelId;_messageHandler;_clientOrigin;onclose;onerror;onmessage;constructor(e){if(!e.allowedOrigins||e.allowedOrigins.length===0)throw new Error("At least one allowed origin must be specified");this._allowedOrigins=e.allowedOrigins,this._channelId=e.channelId||"mcp-default";}async start(){if(this._started)throw new Error("Transport already started");this._messageHandler=e=>{if(console.log({event:e}),!(!this._allowedOrigins.includes(e.origin)&&!this._allowedOrigins.includes("*"))&&!(e.data?.channel!==this._channelId||e.data?.type!=="mcp")&&e.data?.direction==="client-to-server"){this._clientOrigin=e.origin;try{let r=JSONRPCMessageSchema.parse(e.data.payload);this.onmessage?.(r);}catch(r){this.onerror?.(new Error(`Invalid message: ${r}`));}}},window.addEventListener("message",this._messageHandler),this._started=true;}async send(e){if(!this._started)throw new Error("Transport not started");if(!this._clientOrigin)throw new Error("No client connected");window.postMessage({channel:this._channelId,type:"mcp",direction:"server-to-client",payload:e},this._clientOrigin);}async close(){this._messageHandler&&window.removeEventListener("message",this._messageHandler),this._started=false,this.onclose?.();}};var d=class{_port;_extensionId;_portName;_messageHandler;_disconnectHandler;onclose;onerror;onmessage;constructor(e={}){this._extensionId=e.extensionId,this._portName=e.portName||"mcp";}async start(){if(this._port)throw new Error("ExtensionClientTransport already started! If using Client class, note that connect() calls start() automatically.");return new Promise((e,r)=>{if(!chrome?.runtime?.connect){r(new Error("Chrome runtime API not available. This transport must be used in a Chrome extension context."));return}try{this._extensionId?this._port=chrome.runtime.connect(this._extensionId,{name:this._portName}):this._port=chrome.runtime.connect({name:this._portName}),this._messageHandler=s=>{try{let o=JSONRPCMessageSchema.parse(s);this.onmessage?.(o);}catch(o){this.onerror?.(new Error(`Failed to parse message: ${o}`));}},this._disconnectHandler=()=>{this._cleanup(),this.onclose?.();},this._port.onMessage.addListener(this._messageHandler),this._port.onDisconnect.addListener(this._disconnectHandler);let t=chrome.runtime.lastError;if(t){this._cleanup(),r(new Error(`Connection failed: ${t.message}`));return}e();}catch(t){r(t);}})}async send(e,r){if(!this._port)throw new Error("Not connected");try{this._port.postMessage(e);}catch(t){throw new Error(`Failed to send message: ${t}`)}}async close(){if(this._port)try{this._port.disconnect();}catch{}this._cleanup(),this.onclose?.();}_cleanup(){this._port&&(this._messageHandler&&this._port.onMessage.removeListener(this._messageHandler),this._disconnectHandler&&this._port.onDisconnect.removeListener(this._disconnectHandler)),this._port=void 0;}};var h=class{_port;_started=false;_messageHandler;_disconnectHandler;onclose;onerror;onmessage;constructor(e){this._port=e;}async start(){if(this._started)throw new Error("ExtensionServerTransport already started! If using Server class, note that connect() calls start() automatically.");if(!this._port)throw new Error("Port not available");this._started=true,this._messageHandler=e=>{try{let r=JSONRPCMessageSchema.parse(e);this.onmessage?.(r);}catch(r){this.onerror?.(new Error(`Failed to parse message: ${r}`));}},this._disconnectHandler=()=>{this._cleanup(),this.onclose?.();},this._port.onMessage.addListener(this._messageHandler),this._port.onDisconnect.addListener(this._disconnectHandler);}async send(e,r){if(!this._started)throw new Error("Transport not started");if(!this._port)throw new Error("Not connected to client");try{this._port.postMessage(e);}catch(t){throw new Error(`Failed to send message: ${t}`)}}async close(){if(this._started=false,this._port)try{this._port.disconnect();}catch{}this._cleanup(),this.onclose?.();}_cleanup(){this._port&&(this._messageHandler&&this._port.onMessage.removeListener(this._messageHandler),this._disconnectHandler&&this._port.onDisconnect.removeListener(this._disconnectHandler));}};var l="mcp",m=class{_socket;_url;_WebSocket;onclose;onerror;onmessage;constructor(e){this._url=e;}async start(){if(this._socket)throw new Error("WebSocketClientTransport already started! If using Client class, note that connect() calls start() automatically.");if(!this._WebSocket)try{let e=await import('ws');this._WebSocket=e.WebSocket;}catch{throw new Error("Failed to import 'ws' package. Please install it with: npm install ws")}return new Promise((e,r)=>{this._socket=new this._WebSocket(this._url.toString(),{perMessageDeflate:false,...{protocol:l}}),this._socket.on("error",t=>{r(t),this.onerror?.(t);}),this._socket.on("open",()=>{e();}),this._socket.on("close",()=>{this.onclose?.();}),this._socket.on("message",t=>{let s;try{let o=t instanceof Buffer?t.toString("utf-8"):t.toString();s=JSONRPCMessageSchema.parse(JSON.parse(o));}catch(o){this.onerror?.(o);return}this.onmessage?.(s);});})}async close(){this._socket&&this._WebSocket&&this._socket.readyState===this._WebSocket.OPEN&&this._socket.close();}async send(e){return new Promise((r,t)=>{if(!this._socket||!this._WebSocket){t(new Error("Not connected"));return}if(this._socket.readyState!==this._WebSocket.OPEN){t(new Error("WebSocket is not open"));return}this._socket.send(JSON.stringify(e),s=>{s?t(s):r();});})}};var _=class{constructor(e){this._options=e;}_socket;_server;_started=false;_connectionId;onclose;onerror;onmessage;async start(){if(this._started)throw new Error("WebSocketServerTransport already started! If using Server class, note that connect() calls start() automatically.");if(this._started=true,this._options.socket)this._socket=this._options.socket,this.setupSocketHandlers(this._socket);else throw new Error("WebSocketServerTransport requires either a socket ")}setupSocketHandlers(e){e.onmessage=r=>{let t;try{let s=typeof r.data=="string"?r.data:r.data.toString(),o=JSON.parse(s);if(o.connectionId){this._connectionId=o.connectionId;let{connectionId:f,...i}=o;t=JSONRPCMessageSchema.parse(i);}else t=JSONRPCMessageSchema.parse(o);}catch(s){this.onerror?.(s);return}this.onmessage?.(t);},e.onerror=r=>{let t=new Error(`WebSocket error: ${JSON.stringify(r)}`);this.onerror?.(t);},e.onclose=()=>{this._socket=void 0,this.onclose?.();};}async close(){if(this._socket&&(this._socket.close(),this._socket=void 0),this._server)return new Promise(e=>{this._server.close(()=>{this._server=void 0,e();});})}send(e){return new Promise((r,t)=>{if(!this._socket||this._socket.readyState!==WebSocket.OPEN){t(new Error("No active WebSocket connection"));return}try{let s=this._connectionId?{...e,connectionId:this._connectionId}:e;this._socket.send(JSON.stringify(s)),r();}catch(s){t(s);}})}get socket(){return this._socket}get isConnected(){return this._socket?.readyState===WebSocket.OPEN}};var g=class{_socket;_url;_connectionId;onclose;onerror;onmessage;constructor(e){this._url=e.toString();}async start(){if(this._socket)throw new Error("BrowserWebSocketClientTransport already started! If using Client class, note that connect() calls start() automatically.");return new Promise((e,r)=>{try{this._socket=new WebSocket(this._url),this._socket.onopen=()=>{e();},this._socket.onerror=t=>{let s=new Error("WebSocket connection error");r(s),this.onerror?.(s);},this._socket.onclose=()=>{this._socket=void 0,this._connectionId=void 0,this.onclose?.();},this._socket.onmessage=t=>{let s;try{if(s=JSON.parse(t.data),s.connectionId&&!this._connectionId&&(this._connectionId=s.connectionId),s.connectionId){let{connectionId:f,...i}=s;s=i;}let o=JSONRPCMessageSchema.parse(s);this.onmessage?.(o);}catch(o){this.onerror?.(o);}};}catch(t){r(t);}})}async close(){this._socket&&this._socket.readyState===WebSocket.OPEN&&this._socket.close();}async send(e){return new Promise((r,t)=>{if(!this._socket||this._socket.readyState!==WebSocket.OPEN){t(new Error("WebSocket is not connected"));return}try{let s=this._connectionId?{...e,connectionId:this._connectionId}:e;this._socket.send(JSON.stringify(s)),r();}catch(s){t(s);}})}get isConnected(){return this._socket?.readyState===WebSocket.OPEN}};export{g as BrowserWebSocketClientTransport,d as ExtensionClientTransport,h as ExtensionServerTransport,a as TabClientTransport,c as TabServerTransport,m as WebSocketClientTransport,_ as WebSocketServerTransport};//# sourceMappingURL=index.js.map
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/TabClientTransport.ts","../src/TabServerTransport.ts","../src/ExtensionClientTransport.ts","../src/ExtensionServerTransport.ts","../src/WebsocketClientTransport.ts","../src/WebsocketServerTransport.ts"],"names":["TabClientTransport","options","event","message","JSONRPCMessageSchema","error","TabServerTransport","ExtensionClientTransport","resolve","reject","mcpMessage","_options","ExtensionServerTransport","port","SUBPROTOCOL","WebSocketClientTransport","url","ws","data","dataStr","WebSocketServerTransport","socket"],"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\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 message = JSONRPCMessageSchema.parse(JSON.parse(data));\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 this._socket.send(JSON.stringify(message));\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"]}
|
|
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"]}
|