@mcp-b/transports 4.0.0 → 5.0.0
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/LICENSE +1 -1
- package/README.md +130 -101
- package/dist/index.d.ts +86 -829
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +17 -14
- package/dist/index.d.ts.map +0 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
| **Secure by Default** | Origin validation, CORS configuration, and Chrome's secure messaging APIs |
|
|
21
21
|
| **AI-Agent Ready** | Built specifically for MCP, the standard protocol for AI tool integration |
|
|
22
22
|
| **TypeScript First** | Full type safety with comprehensive type definitions |
|
|
23
|
-
| **
|
|
23
|
+
| **MCP SDK v2** | Uses the split MCP server and core packages |
|
|
24
24
|
| **Works Everywhere** | Chrome, Firefox, Edge, and any Chromium-based browser |
|
|
25
25
|
|
|
26
26
|
## Use Cases
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
## Installation
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
npm install @mcp-b/transports
|
|
37
|
+
npm install @mcp-b/transports @modelcontextprotocol/client @modelcontextprotocol/server zod
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
## Transport Types
|
|
@@ -49,7 +49,8 @@ Use `ExtensionClientTransport` and `ExtensionServerTransport` for communication
|
|
|
49
49
|
|
|
50
50
|
### Extension External Transports (Cross-Extension Communication)
|
|
51
51
|
|
|
52
|
-
Use `
|
|
52
|
+
Use `ExtensionClientTransport` and `ExtensionServerTransport` with an extension ID and
|
|
53
|
+
`chrome.runtime.onConnectExternal` for communication between different browser extensions.
|
|
53
54
|
|
|
54
55
|
## Tab Transport Examples
|
|
55
56
|
|
|
@@ -59,7 +60,7 @@ Create an MCP server in your web page and expose it via `TabServerTransport`:
|
|
|
59
60
|
|
|
60
61
|
```typescript
|
|
61
62
|
import { TabServerTransport } from '@mcp-b/transports';
|
|
62
|
-
import { McpServer } from '@modelcontextprotocol/
|
|
63
|
+
import { McpServer } from '@modelcontextprotocol/server';
|
|
63
64
|
import { z } from 'zod';
|
|
64
65
|
|
|
65
66
|
// Create MCP server with tools
|
|
@@ -74,11 +75,13 @@ const server = new McpServer(
|
|
|
74
75
|
);
|
|
75
76
|
|
|
76
77
|
// Register a tool
|
|
77
|
-
server.
|
|
78
|
+
server.registerTool(
|
|
78
79
|
'createTodo',
|
|
79
|
-
'Creates a new todo item for the current user',
|
|
80
80
|
{
|
|
81
|
-
|
|
81
|
+
description: 'Creates a new todo item for the current user',
|
|
82
|
+
inputSchema: z.object({
|
|
83
|
+
todoText: z.string().describe('The content of the todo item.'),
|
|
84
|
+
}),
|
|
82
85
|
},
|
|
83
86
|
async (args) => {
|
|
84
87
|
// Implementation here
|
|
@@ -106,24 +109,23 @@ Connect to the server from within the same page or from an extension content scr
|
|
|
106
109
|
|
|
107
110
|
```typescript
|
|
108
111
|
import { TabClientTransport } from '@mcp-b/transports';
|
|
109
|
-
import { Client } from '@modelcontextprotocol/
|
|
112
|
+
import { Client } from '@modelcontextprotocol/client';
|
|
110
113
|
|
|
111
114
|
// Create transport with target origin
|
|
112
115
|
const transport = new TabClientTransport({
|
|
113
116
|
targetOrigin: window.location.origin,
|
|
114
117
|
});
|
|
115
118
|
|
|
116
|
-
// Discover available servers
|
|
117
|
-
const availableServers = await transport.discover();
|
|
118
|
-
if (availableServers.length > 0) {
|
|
119
|
-
console.log(`Found server: ${availableServers[0].implementation.name}`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
119
|
// Create and connect client
|
|
123
|
-
const client = new Client(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
120
|
+
const client = new Client(
|
|
121
|
+
{
|
|
122
|
+
name: 'ExtensionProxyClient',
|
|
123
|
+
version: '1.0.0',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
versionNegotiation: { mode: 'auto' },
|
|
127
|
+
}
|
|
128
|
+
);
|
|
127
129
|
|
|
128
130
|
await client.connect(transport);
|
|
129
131
|
|
|
@@ -156,28 +158,23 @@ Create an MCP server inside an iframe that can be accessed by the parent page:
|
|
|
156
158
|
|
|
157
159
|
```typescript
|
|
158
160
|
import { IframeChildTransport } from '@mcp-b/transports';
|
|
159
|
-
import {
|
|
161
|
+
import { McpServer } from '@modelcontextprotocol/server';
|
|
160
162
|
import { z } from 'zod';
|
|
161
163
|
|
|
162
164
|
// Create MCP server
|
|
163
|
-
const server = new
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
capabilities: {
|
|
170
|
-
tools: {},
|
|
171
|
-
},
|
|
172
|
-
}
|
|
173
|
-
);
|
|
165
|
+
const server = new McpServer({
|
|
166
|
+
name: 'IframeApp',
|
|
167
|
+
version: '1.0.0',
|
|
168
|
+
});
|
|
174
169
|
|
|
175
170
|
// Register tools
|
|
176
|
-
server.
|
|
171
|
+
server.registerTool(
|
|
177
172
|
'getIframeData',
|
|
178
|
-
'Get data from the iframe application',
|
|
179
173
|
{
|
|
180
|
-
|
|
174
|
+
description: 'Get data from the iframe application',
|
|
175
|
+
inputSchema: z.object({
|
|
176
|
+
key: z.string().describe('Data key to retrieve'),
|
|
177
|
+
}),
|
|
181
178
|
},
|
|
182
179
|
async (args) => {
|
|
183
180
|
return {
|
|
@@ -206,7 +203,7 @@ Connect from the parent page to the iframe's MCP server:
|
|
|
206
203
|
|
|
207
204
|
```typescript
|
|
208
205
|
import { IframeParentTransport } from '@mcp-b/transports';
|
|
209
|
-
import { Client } from '@modelcontextprotocol/
|
|
206
|
+
import { Client } from '@modelcontextprotocol/client';
|
|
210
207
|
|
|
211
208
|
// Get reference to iframe element
|
|
212
209
|
const iframe = document.querySelector('iframe');
|
|
@@ -220,10 +217,15 @@ iframe.addEventListener('load', async () => {
|
|
|
220
217
|
});
|
|
221
218
|
|
|
222
219
|
// Create MCP client
|
|
223
|
-
const client = new Client(
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
220
|
+
const client = new Client(
|
|
221
|
+
{
|
|
222
|
+
name: 'ParentPage',
|
|
223
|
+
version: '1.0.0',
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
versionNegotiation: { mode: 'auto' },
|
|
227
|
+
}
|
|
228
|
+
);
|
|
227
229
|
|
|
228
230
|
// Connect and use
|
|
229
231
|
await client.connect(transport);
|
|
@@ -247,13 +249,12 @@ iframe.addEventListener('load', async () => {
|
|
|
247
249
|
- `iframe` (required): Reference to the HTMLIFrameElement
|
|
248
250
|
- `targetOrigin` (required): Expected origin of the iframe (for security)
|
|
249
251
|
- `channelId`: Override the default channel identifier (default: `mcp-iframe`)
|
|
250
|
-
- `checkReadyRetryMs`:
|
|
252
|
+
- `checkReadyRetryMs`: Retry interval while `iframe.contentWindow` is unavailable (default: 250ms)
|
|
251
253
|
|
|
252
254
|
#### IframeChildTransport Options
|
|
253
255
|
|
|
254
256
|
- `allowedOrigins` (required): Whitelist of parent origins allowed to connect (for security)
|
|
255
257
|
- `channelId`: Override the default channel identifier (default: `mcp-iframe`)
|
|
256
|
-
- `serverReadyRetryMs`: Interval to retry broadcasting ready signal to parent (default: 250ms)
|
|
257
258
|
|
|
258
259
|
### Cross-Origin Support
|
|
259
260
|
|
|
@@ -262,7 +263,7 @@ Iframe transports are designed for cross-origin communication:
|
|
|
262
263
|
- Parent and iframe can be on different domains
|
|
263
264
|
- Origin validation is performed on both sides
|
|
264
265
|
- Uses secure `postMessage` API
|
|
265
|
-
-
|
|
266
|
+
- The parent retries its ready check until the iframe window is available
|
|
266
267
|
|
|
267
268
|
## Extension Transport Examples
|
|
268
269
|
|
|
@@ -272,18 +273,20 @@ The extension background script acts as a hub, aggregating tools from multiple t
|
|
|
272
273
|
|
|
273
274
|
```typescript
|
|
274
275
|
import { ExtensionServerTransport } from '@mcp-b/transports';
|
|
275
|
-
import { McpServer } from '@modelcontextprotocol/
|
|
276
|
+
import { McpServer } from '@modelcontextprotocol/server';
|
|
276
277
|
|
|
277
278
|
class McpHub {
|
|
278
|
-
private server: McpServer;
|
|
279
|
-
|
|
280
279
|
constructor() {
|
|
281
|
-
this.
|
|
280
|
+
this.setupConnections();
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
private createServer() {
|
|
284
|
+
const server = new McpServer({
|
|
282
285
|
name: 'Extension-Hub',
|
|
283
286
|
version: '1.0.0',
|
|
284
287
|
});
|
|
285
|
-
|
|
286
|
-
|
|
288
|
+
// Register tools backed by the hub's shared application state here.
|
|
289
|
+
return server;
|
|
287
290
|
}
|
|
288
291
|
|
|
289
292
|
private setupConnections() {
|
|
@@ -297,29 +300,38 @@ class McpHub {
|
|
|
297
300
|
}
|
|
298
301
|
|
|
299
302
|
private async handleUiConnection(port: chrome.runtime.Port) {
|
|
303
|
+
const server = this.createServer();
|
|
300
304
|
const transport = new ExtensionServerTransport(port);
|
|
301
|
-
await
|
|
305
|
+
await server.connect(transport);
|
|
302
306
|
}
|
|
303
307
|
}
|
|
304
308
|
```
|
|
305
309
|
|
|
310
|
+
Each `McpServer` owns one protocol session, so every accepted port gets a fresh server. Keep the
|
|
311
|
+
hub's shared application state outside the per-connection server.
|
|
312
|
+
|
|
306
313
|
### Content Script Bridge
|
|
307
314
|
|
|
308
315
|
Content scripts act as a bridge between the page's MCP server and the extension:
|
|
309
316
|
|
|
310
317
|
```typescript
|
|
311
318
|
import { TabClientTransport } from '@mcp-b/transports';
|
|
312
|
-
import { Client } from '@modelcontextprotocol/
|
|
319
|
+
import { Client } from '@modelcontextprotocol/client';
|
|
313
320
|
|
|
314
321
|
// Connect to the page's MCP server
|
|
315
322
|
const transport = new TabClientTransport({
|
|
316
323
|
targetOrigin: window.location.origin,
|
|
317
324
|
});
|
|
318
325
|
|
|
319
|
-
const client = new Client(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
326
|
+
const client = new Client(
|
|
327
|
+
{
|
|
328
|
+
name: 'ExtensionProxyClient',
|
|
329
|
+
version: '1.0.0',
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
versionNegotiation: { mode: 'auto' },
|
|
333
|
+
}
|
|
334
|
+
);
|
|
323
335
|
|
|
324
336
|
// Connect to extension background
|
|
325
337
|
const backgroundPort = chrome.runtime.connect({
|
|
@@ -359,7 +371,7 @@ Connect from the extension's sidebar or popup to use tools from all connected pa
|
|
|
359
371
|
|
|
360
372
|
```typescript
|
|
361
373
|
import { ExtensionClientTransport } from '@mcp-b/transports';
|
|
362
|
-
import { Client } from '@modelcontextprotocol/
|
|
374
|
+
import { Client } from '@modelcontextprotocol/client';
|
|
363
375
|
|
|
364
376
|
// Create transport - connects to the extension's background script
|
|
365
377
|
const transport = new ExtensionClientTransport({
|
|
@@ -367,10 +379,15 @@ const transport = new ExtensionClientTransport({
|
|
|
367
379
|
});
|
|
368
380
|
|
|
369
381
|
// Create MCP client
|
|
370
|
-
const client = new Client(
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
382
|
+
const client = new Client(
|
|
383
|
+
{
|
|
384
|
+
name: 'Extension Sidepanel',
|
|
385
|
+
version: '1.0.0',
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
versionNegotiation: { mode: 'auto' },
|
|
389
|
+
}
|
|
390
|
+
);
|
|
374
391
|
|
|
375
392
|
// Connect and use
|
|
376
393
|
await client.connect(transport);
|
|
@@ -392,33 +409,41 @@ const result = await client.callTool({
|
|
|
392
409
|
Create an MCP server in Extension 1 that can be accessed by other extensions:
|
|
393
410
|
|
|
394
411
|
```typescript
|
|
395
|
-
import {
|
|
396
|
-
import { McpServer } from '@modelcontextprotocol/
|
|
412
|
+
import { ExtensionServerTransport } from '@mcp-b/transports';
|
|
413
|
+
import { McpServer } from '@modelcontextprotocol/server';
|
|
397
414
|
import { z } from 'zod';
|
|
398
415
|
|
|
399
|
-
|
|
400
|
-
const server = new McpServer(
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
);
|
|
416
|
+
function createServer() {
|
|
417
|
+
const server = new McpServer(
|
|
418
|
+
{
|
|
419
|
+
name: 'MyExtensionAPI',
|
|
420
|
+
version: '1.0.0',
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
instructions: 'Extension API for cross-extension communication',
|
|
424
|
+
}
|
|
425
|
+
);
|
|
409
426
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
427
|
+
server.registerTool(
|
|
428
|
+
'getBookmarks',
|
|
429
|
+
{
|
|
430
|
+
description: 'Retrieves user bookmarks',
|
|
431
|
+
inputSchema: z.object({}),
|
|
432
|
+
},
|
|
433
|
+
async () => {
|
|
434
|
+
const bookmarks = await chrome.bookmarks.getTree();
|
|
435
|
+
return {
|
|
436
|
+
content: [
|
|
437
|
+
{
|
|
438
|
+
type: 'text',
|
|
439
|
+
text: JSON.stringify(bookmarks, null, 2),
|
|
440
|
+
},
|
|
441
|
+
],
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
);
|
|
445
|
+
return server;
|
|
446
|
+
}
|
|
422
447
|
|
|
423
448
|
// Set up external connection listener in background script
|
|
424
449
|
chrome.runtime.onConnectExternal.addListener(async (port) => {
|
|
@@ -429,6 +454,7 @@ chrome.runtime.onConnectExternal.addListener(async (port) => {
|
|
|
429
454
|
return;
|
|
430
455
|
}
|
|
431
456
|
|
|
457
|
+
const server = createServer();
|
|
432
458
|
const transport = new ExtensionServerTransport(port);
|
|
433
459
|
await server.connect(transport);
|
|
434
460
|
}
|
|
@@ -440,8 +466,8 @@ chrome.runtime.onConnectExternal.addListener(async (port) => {
|
|
|
440
466
|
Connect from Extension 2 to use Extension 1's MCP server:
|
|
441
467
|
|
|
442
468
|
```typescript
|
|
443
|
-
import {
|
|
444
|
-
import { Client } from '@modelcontextprotocol/
|
|
469
|
+
import { ExtensionClientTransport } from '@mcp-b/transports';
|
|
470
|
+
import { Client } from '@modelcontextprotocol/client';
|
|
445
471
|
|
|
446
472
|
// Create transport targeting Extension 1
|
|
447
473
|
const transport = new ExtensionClientTransport({
|
|
@@ -450,10 +476,15 @@ const transport = new ExtensionClientTransport({
|
|
|
450
476
|
});
|
|
451
477
|
|
|
452
478
|
// Create MCP client
|
|
453
|
-
const client = new Client(
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
479
|
+
const client = new Client(
|
|
480
|
+
{
|
|
481
|
+
name: 'ClientExtension',
|
|
482
|
+
version: '1.0.0',
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
versionNegotiation: { mode: 'auto' },
|
|
486
|
+
}
|
|
487
|
+
);
|
|
457
488
|
|
|
458
489
|
// Connect and use
|
|
459
490
|
await client.connect(transport);
|
|
@@ -493,18 +524,17 @@ const result = await client.callTool({
|
|
|
493
524
|
|
|
494
525
|
### Extension External Transport Flow
|
|
495
526
|
|
|
496
|
-
1. Extension 1 creates `
|
|
497
|
-
2. Extension 2 creates `
|
|
527
|
+
1. Extension 1 creates `ExtensionServerTransport` instances from `chrome.runtime.onConnectExternal`
|
|
528
|
+
2. Extension 2 creates an `ExtensionClientTransport` with Extension 1's ID
|
|
498
529
|
3. Communication happens through Chrome's secure cross-extension messaging
|
|
499
530
|
4. Server extension can validate connections and control access
|
|
500
531
|
|
|
501
532
|
## Key Features
|
|
502
533
|
|
|
503
|
-
- **
|
|
504
|
-
- **
|
|
534
|
+
- **Ready Handshake**: Tab and iframe clients wait for their server before sending
|
|
535
|
+
- **Origin Controls**: Restrict incoming and outgoing `postMessage` origins
|
|
505
536
|
- **Cross-Extension Communication**: Extensions can expose APIs to other extensions
|
|
506
537
|
- **Tool Namespacing**: Extension hub prefixes tools to avoid conflicts
|
|
507
|
-
- **Connection Management**: Automatic cleanup when tabs close
|
|
508
538
|
- **Type Safety**: Full TypeScript support with proper typing
|
|
509
539
|
|
|
510
540
|
## Security Considerations
|
|
@@ -524,12 +554,12 @@ MCP is an open protocol that standardizes how AI applications connect to externa
|
|
|
524
554
|
|
|
525
555
|
### Which transport should I use?
|
|
526
556
|
|
|
527
|
-
| Scenario | Recommended Transport
|
|
528
|
-
| ---------------------------- |
|
|
529
|
-
| Same-page communication | `TabServerTransport` / `TabClientTransport`
|
|
530
|
-
| Parent page to iframe | `IframeParentTransport` / `IframeChildTransport`
|
|
531
|
-
| Browser extension to webpage | `ExtensionClientTransport` / `ExtensionServerTransport`
|
|
532
|
-
| Extension to extension | `
|
|
557
|
+
| Scenario | Recommended Transport |
|
|
558
|
+
| ---------------------------- | ------------------------------------------------------- |
|
|
559
|
+
| Same-page communication | `TabServerTransport` / `TabClientTransport` |
|
|
560
|
+
| Parent page to iframe | `IframeParentTransport` / `IframeChildTransport` |
|
|
561
|
+
| Browser extension to webpage | `ExtensionClientTransport` / `ExtensionServerTransport` |
|
|
562
|
+
| Extension to extension | `ExtensionClientTransport` / `ExtensionServerTransport` |
|
|
533
563
|
|
|
534
564
|
### Is this compatible with Claude Desktop, Cursor, or VS Code Copilot?
|
|
535
565
|
|
|
@@ -557,9 +587,8 @@ Yes! `TabServerTransport` and `TabClientTransport` work entirely within a web pa
|
|
|
557
587
|
|
|
558
588
|
- [`@mcp-b/global`](https://docs.mcp-b.ai/packages/global/reference) - Full MCP-B browser runtime
|
|
559
589
|
- [`@mcp-b/react-webmcp`](https://docs.mcp-b.ai/packages/react-webmcp/reference) - React hooks for MCP tool registration
|
|
560
|
-
- [`@mcp-b/extension-tools`](https://docs.mcp-b.ai/packages/extension-tools/reference) - 62+ Chrome Extension API tools for MCP
|
|
561
590
|
- [`chrome-devtools-mcp`](https://github.com/ChromeDevTools/chrome-devtools-mcp) - Upstream Chrome DevTools MCP server
|
|
562
|
-
- [`@modelcontextprotocol/
|
|
591
|
+
- [`@modelcontextprotocol/client`](https://www.npmjs.com/package/@modelcontextprotocol/client) and [`@modelcontextprotocol/server`](https://www.npmjs.com/package/@modelcontextprotocol/server) - Official MCP TypeScript SDK v2 packages
|
|
563
592
|
|
|
564
593
|
## Resources
|
|
565
594
|
|