Skip to content

Commit 8e5a024

Browse files
committed
add suport for browser context transport
1 parent 0fa2397 commit 8e5a024

File tree

3 files changed

+790
-0
lines changed

3 files changed

+790
-0
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# BrowserContextTransport
2+
3+
Enables communication between different browser contexts using the MessageChannel API.
4+
5+
## Motivation
6+
7+
When building agentic chat applications in the browser with MCP, you need a reliable way for components to communicate across browser security boundaries. For example:
8+
9+
- Chat UI running in a sandboxed iframe needs to talk to MCP clients/servers
10+
- Agent tools executing in web workers need to communicate with the main thread
11+
- Security-sensitive components isolated in separate contexts need to exchange messages
12+
13+
Other transports don't work well for these browser scenarios:
14+
- **InMemoryTransport**: Can't cross browser context boundaries (iframes, workers)
15+
- **WebSocketTransport**: Requires network connection, server infrastructure, and adds latency
16+
- **SSETransport**: Limited to one-way communication, requires network connection
17+
18+
## Use Case
19+
20+
```mermaid
21+
flowchart LR
22+
subgraph Browser["Browser"]
23+
subgraph IFrame["Iframe"]
24+
ChatUI["UI"] --> Client["Client"]
25+
Client --> Transport["Transport"]
26+
end
27+
Transport --> Server["Server"]
28+
Server --> AppLogic["App"]
29+
end
30+
31+
classDef component fill:#e1f5fe,stroke:#01579b,stroke-width:1px,rx:5px,ry:5px;
32+
classDef container fill:#f5f5f5,stroke:#333,stroke-width:1px;
33+
class Client,Server,AppLogic,ChatUI,Transport component;
34+
```
35+
36+
## Quick Start
37+
38+
### Creating a Transport Pair
39+
40+
Most basic use case - both ends in same context:
41+
42+
```typescript
43+
const [clientTransport, serverTransport] = BrowserContextTransport.createChannelPair();
44+
const client = new Client(clientTransport);
45+
const server = new Server(serverTransport);
46+
```
47+
48+
### With Iframes
49+
50+
Special code is needed for iframes because they're separate JavaScript execution contexts with their own memory space. You must use `postMessage` to transfer a `MessagePort`:
51+
52+
```typescript
53+
// Parent window
54+
const iframe = document.getElementById('myIframe');
55+
const channel = new MessageChannel();
56+
const clientTransport = new BrowserContextTransport(channel.port1);
57+
const client = new Client(clientTransport);
58+
iframe.contentWindow.postMessage('init', '*', [channel.port2]);
59+
60+
// Inside iframe
61+
window.addEventListener('message', (event) => {
62+
if (event.data === 'init' && event.ports[0]) {
63+
const serverTransport = new BrowserContextTransport(event.ports[0]);
64+
const server = new Server(serverTransport);
65+
}
66+
});
67+
```
68+
69+
### With Workers
70+
71+
Workers also require special handling since they run in isolated threads. Like iframes, they need a `MessagePort` transferred via `postMessage`:
72+
73+
```typescript
74+
// Main thread
75+
const worker = new Worker('worker.js');
76+
const channel = new MessageChannel();
77+
const clientTransport = new BrowserContextTransport(channel.port1);
78+
worker.postMessage('init', [channel.port2]);
79+
80+
// In worker
81+
self.addEventListener('message', (event) => {
82+
if (event.data === 'init') {
83+
const serverTransport = new BrowserContextTransport(event.ports[0]);
84+
const server = new Server(serverTransport);
85+
}
86+
});
87+
```

0 commit comments

Comments
 (0)