> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mcp-b.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# @mcp-b/transports

> Reference for browser transport classes, options, and transport-specific security boundaries.

Browser transport implementations for the Model Context Protocol. Each transport class implements the MCP `Transport` interface and handles JSON-RPC 2.0 message serialization, origin validation, and connection lifecycle.

## Installation

```bash theme={null}
pnpm add @mcp-b/transports
```

Peer dependency: `@mcp-b/webmcp-ts-sdk` (included transitively).

## Minimal example

<Snippet file="snippets/packages/transports-quickstart.ts" />

## Which transport to use

| Scenario                 | Server                                         | Client                                                  |
| ------------------------ | ---------------------------------------------- | ------------------------------------------------------- |
| Same-page communication  | `TabServerTransport`                           | `TabClientTransport`                                    |
| Parent page to iframe    | `IframeChildTransport` (in iframe)             | `IframeParentTransport` (in parent)                     |
| Extension to webpage     | `ExtensionServerTransport` (in background)     | `ExtensionClientTransport` (in sidebar/popup)           |
| Extension to extension   | `ExtensionServerTransport` (in host extension) | `ExtensionExternalClientTransport` (in guest extension) |
| User script to extension | `UserScriptServerTransport` (in background)    | `UserScriptClientTransport` (in user script)            |

***

## Tab transports

In-page communication via `window.postMessage`. Both server and client run in the same browser tab.

### TabServerTransport

Listens for MCP messages on the current window. Broadcasts a `mcp-server-ready` signal on start.

```typescript theme={null}
import { TabServerTransport } from '@mcp-b/transports';

const transport = new TabServerTransport({
  allowedOrigins: ['https://example.com'],
});
await server.connect(transport);
```

#### TabServerTransportOptions

| Option           | Type       | Required | Default         | Description                                                                                                          |
| ---------------- | ---------- | -------- | --------------- | -------------------------------------------------------------------------------------------------------------------- |
| `allowedOrigins` | `string[]` | Yes      | --              | Origins permitted to send messages. Use `["*"]` to allow any origin.                                                 |
| `channelId`      | `string`   | No       | `"mcp-default"` | Channel identifier for message routing. Multiple transports can coexist on the same page with different channel IDs. |

#### Behavior

* Validates `event.origin` against `allowedOrigins` for every incoming message.
* Tracks pending requests and sends interrupted responses during `beforeunload` if the page navigates while a tool call is in progress.
* Cleans up stale requests after 5 minutes.
* Posts `mcp-server-stopped` on close.

### TabClientTransport

Connects to a `TabServerTransport` in the same window. Waits for a server-ready handshake before sending messages.

```typescript theme={null}
import { TabClientTransport } from '@mcp-b/transports';

const transport = new TabClientTransport({
  targetOrigin: window.location.origin,
});
await client.connect(transport);
```

#### TabClientTransportOptions

| Option           | Type     | Required | Default         | Description                                                                                                                       |
| ---------------- | -------- | -------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `targetOrigin`   | `string` | No       | `"*"`           | Expected origin of the server window. Messages from other origins are ignored.                                                    |
| `channelId`      | `string` | No       | `"mcp-default"` | Channel identifier for message routing.                                                                                           |
| `requestTimeout` | `number` | No       | `10000`         | Timeout in milliseconds for requests. If the server does not respond in time, a JSON-RPC error with code `-32000` is synthesized. |

#### Properties

| Property             | Type            | Description                                                                     |
| -------------------- | --------------- | ------------------------------------------------------------------------------- |
| `serverReadyPromise` | `Promise<void>` | Resolves when the server signals readiness. `send()` awaits this automatically. |

#### Server discovery

`TabClientTransport` does not have a standalone `discover()` method. The server-ready handshake (`mcp-check-ready` / `mcp-server-ready`) is handled internally during `start()`.

***

## Iframe transports

Cross-origin communication between a parent page and an iframe. Uses `window.postMessage` with retry-based ready handshakes to handle iframe loading timing.

### IframeParentTransport

Client-side transport for the parent page. Sends messages into the iframe's `contentWindow`.

```typescript theme={null}
import { IframeParentTransport } from '@mcp-b/transports';

const iframe = document.querySelector('iframe');
const transport = new IframeParentTransport({
  iframe,
  targetOrigin: 'https://iframe-app.com',
});
await client.connect(transport);
```

#### IframeParentTransportOptions

| Option              | Type                | Required | Default        | Description                                                                           |
| ------------------- | ------------------- | -------- | -------------- | ------------------------------------------------------------------------------------- |
| `iframe`            | `HTMLIFrameElement` | Yes      | --             | Reference to the iframe element.                                                      |
| `targetOrigin`      | `string`            | No       | `"*"`          | Expected origin of the iframe for `postMessage` security.                             |
| `channelId`         | `string`            | No       | `"mcp-iframe"` | Channel identifier for message routing.                                               |
| `checkReadyRetryMs` | `number`            | No       | `250`          | Interval in milliseconds to retry the ready handshake if the iframe is not yet ready. |

#### Properties

| Property             | Type            | Description                                          |
| -------------------- | --------------- | ---------------------------------------------------- |
| `serverReadyPromise` | `Promise<void>` | Resolves when the iframe's server signals readiness. |

### IframeChildTransport

Server-side transport for code running inside an iframe. Sends messages to `window.parent`.

```typescript theme={null}
import { IframeChildTransport } from '@mcp-b/transports';

const transport = new IframeChildTransport({
  allowedOrigins: ['https://parent-app.com'],
});
await server.connect(transport);
```

#### IframeChildTransportOptions

| Option               | Type       | Required | Default        | Description                                                                    |
| -------------------- | ---------- | -------- | -------------- | ------------------------------------------------------------------------------ |
| `allowedOrigins`     | `string[]` | Yes      | --             | Parent origins permitted to connect. Use `["*"]` to allow any origin.          |
| `channelId`          | `string`   | No       | `"mcp-iframe"` | Channel identifier for message routing.                                        |
| `serverReadyRetryMs` | `number`   | No       | `250`          | Interval in milliseconds to retry broadcasting the ready signal to the parent. |

***

## Extension transports

Communication between Chrome extension components using `chrome.runtime.Port`. Used for connecting content scripts, sidebars, and popups to the extension's background service worker.

### ExtensionServerTransport

Wraps a `chrome.runtime.Port` to handle a single client connection. Runs in the background service worker.

```typescript theme={null}
import { ExtensionServerTransport } from '@mcp-b/transports';

chrome.runtime.onConnect.addListener((port) => {
  if (port.name === 'mcp') {
    const transport = new ExtensionServerTransport(port);
    await server.connect(transport);
  }
});
```

#### Constructor

```typescript theme={null}
new ExtensionServerTransport(port: chrome.runtime.Port, options?: ExtensionServerTransportOptions)
```

#### ExtensionServerTransportOptions

| Option              | Type      | Required | Default | Description                                                        |
| ------------------- | --------- | -------- | ------- | ------------------------------------------------------------------ |
| `keepAlive`         | `boolean` | No       | `true`  | Send periodic keep-alive pings to prevent service worker shutdown. |
| `keepAliveInterval` | `number`  | No       | `1000`  | Keep-alive interval in milliseconds.                               |

#### Methods

| Method                | Returns                                                             | Description            |
| --------------------- | ------------------------------------------------------------------- | ---------------------- |
| `getConnectionInfo()` | `{ connectedAt, lastMessageAt, messageCount, uptime, isConnected }` | Connection statistics. |

### ExtensionClientTransport

Connects to the extension's background service worker via `chrome.runtime.connect`. Supports automatic reconnection with exponential backoff.

```typescript theme={null}
import { ExtensionClientTransport } from '@mcp-b/transports';

const transport = new ExtensionClientTransport({
  portName: 'mcp',
});
await client.connect(transport);
```

#### ExtensionClientTransportOptions

| Option                       | Type      | Required | Default | Description                                                                                                                                                        |
| ---------------------------- | --------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `extensionId`                | `string`  | No       | --      | Extension ID to connect to. Omit for same-extension connections. When provided, uses `chrome.runtime.connect(extensionId, ...)` for cross-extension communication. |
| `portName`                   | `string`  | No       | `"mcp"` | Port name for the connection.                                                                                                                                      |
| `autoReconnect`              | `boolean` | No       | `true`  | Reconnect automatically on disconnect.                                                                                                                             |
| `maxReconnectAttempts`       | `number`  | No       | `10`    | Maximum reconnection attempts before giving up.                                                                                                                    |
| `reconnectDelay`             | `number`  | No       | `1000`  | Initial reconnection delay in milliseconds.                                                                                                                        |
| `maxReconnectDelay`          | `number`  | No       | `30000` | Maximum reconnection delay in milliseconds.                                                                                                                        |
| `reconnectBackoffMultiplier` | `number`  | No       | `1.5`   | Multiplier applied to the delay after each failed attempt.                                                                                                         |

***

## User script transports

Communication between Chrome MV3 user scripts and the extension's background service worker. Connections arrive via `chrome.runtime.onUserScriptConnect` on the extension side.

### UserScriptServerTransport

Identical in API to `ExtensionServerTransport`. Wraps a `chrome.runtime.Port` received from a user script connection.

```typescript theme={null}
import { UserScriptServerTransport } from '@mcp-b/transports';

chrome.runtime.onUserScriptConnect.addListener((port) => {
  const transport = new UserScriptServerTransport(port);
  await server.connect(transport);
});
```

#### UserScriptServerTransportOptions

| Option              | Type      | Required | Default | Description                          |
| ------------------- | --------- | -------- | ------- | ------------------------------------ |
| `keepAlive`         | `boolean` | No       | `true`  | Send periodic keep-alive pings.      |
| `keepAliveInterval` | `number`  | No       | `1000`  | Keep-alive interval in milliseconds. |

### UserScriptClientTransport

Identical in API to `ExtensionClientTransport`. Connects from a user script context to the extension background.

#### UserScriptClientTransportOptions

| Option                       | Type      | Required | Default | Description                                 |
| ---------------------------- | --------- | -------- | ------- | ------------------------------------------- |
| `extensionId`                | `string`  | No       | --      | Extension ID to connect to.                 |
| `portName`                   | `string`  | No       | `"mcp"` | Port name for the connection.               |
| `autoReconnect`              | `boolean` | No       | `true`  | Reconnect automatically on disconnect.      |
| `maxReconnectAttempts`       | `number`  | No       | `10`    | Maximum reconnection attempts.              |
| `reconnectDelay`             | `number`  | No       | `1000`  | Initial reconnection delay in milliseconds. |
| `maxReconnectDelay`          | `number`  | No       | `30000` | Maximum reconnection delay in milliseconds. |
| `reconnectBackoffMultiplier` | `number`  | No       | `1.5`   | Backoff multiplier per failed attempt.      |

***

## Security

All transports enforce origin or connection validation:

| Transport type     | Security mechanism                                                                                                                |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
| Tab                | `allowedOrigins` on server, `targetOrigin` on client. Messages from non-matching origins are silently dropped.                    |
| Iframe             | Same as tab transports. Cross-origin `postMessage` with origin checks on both sides.                                              |
| Extension          | Chrome's port-based messaging API. Only code within the extension (or extensions listed in `externally_connectable`) can connect. |
| Extension External | Requires `externally_connectable` in `manifest.json`. Server should validate `port.sender.id` before accepting connections.       |
| User Script        | Chrome's `onUserScriptConnect` API. Only registered user scripts can initiate connections.                                        |

<Warning>
  Setting `allowedOrigins` to `["*"]` or `targetOrigin` to `"*"` disables origin validation. Use
  specific origins in production.
</Warning>

## Common transport interface

Every transport class implements the MCP `Transport` interface:

| Member          | Type                                | Description                            |
| --------------- | ----------------------------------- | -------------------------------------- |
| `start()`       | `Promise<void>`                     | Begin listening for messages.          |
| `send(message)` | `Promise<void>`                     | Send a JSON-RPC 2.0 message.           |
| `close()`       | `Promise<void>`                     | Stop listening and clean up resources. |
| `onmessage`     | `(message: JSONRPCMessage) => void` | Callback for incoming messages.        |
| `onerror`       | `(error: Error) => void`            | Callback for errors.                   |
| `onclose`       | `() => void`                        | Callback when the transport closes.    |

## Related

* [Transports and bridges](/explanation/architecture/transports-and-bridges) for the conceptual architecture behind transport design
* [Bridge tools across iframes](/how-to/bridge-tools-across-iframes) for a step-by-step iframe bridging guide
* [Connect desktop agents with local relay](/how-to/connect-desktop-agents-with-local-relay) for stdio-to-browser bridging
* [@mcp-b/mcp-iframe](/packages/mcp-iframe/reference) for the high-level `<mcp-iframe>` custom element that wraps iframe transports
