# @lensmcp/bridge

The build-agnostic **browser-event bridge** for LensMCP.

A tiny WebSocket server that the injected [`@lensmcp/client-runtime`](../client-runtime)
connects to, forwarding every observed browser event (errors, console, fetch,
route changes, and pre-formed React/Valtio publishes) onto the LensMCP event
bus — either in-process or, more usually, cross-process over the same
`LENSMCP_EVENT_FILE` / `LENSMCP_UDS` / `LENSMCP_IPC_SOCKET` transport the
MCP server tails.

This logic used to live **inside** `@lensmcp/vite-plugin`, which is why
LensMCP only worked for Vite apps. It was lifted out here so the exact same
bridge can run:

- **embedded** in the Vite dev server (the plugin calls `createBridgeServer`
  on an ephemeral port), or
- **standalone** as a sidecar on a fixed port for **webpack**, **Next.js**,
  or **no-build** hosts — where the browser runtime finds the endpoint by a
  known URL (`ws://127.0.0.1:5747` by default) instead of one a bundler baked
  in.

## Standalone

```bash
LENSMCP_EVENT_FILE=.lensmcp/events.jsonl node bridge.js
# or
lensmcp bridge
```

| Env | Default | Meaning |
| --- | --- | --- |
| `LENSMCP_WS_HOST` | `127.0.0.1` | bind host |
| `LENSMCP_WS_PORT` | `5747` | bind port (`0` = ephemeral) |
| `LENSMCP_SESSION_ID` | — | session id stamped on each event |
| `LENSMCP_EVENT_FILE` | — | JSONL sink the MCP server ingests |

Point the browser at it with `@lensmcp/client-runtime/auto` (zero build):

```ts
import '@lensmcp/client-runtime/auto';
```

## Embedding

```ts
import { createBridgeServer } from '@lensmcp/bridge';

const bridge = await createBridgeServer({ port: 0, bus });
console.log(bridge.port);
await bridge.close();
```

The bridge is **strictly passive**: it never mutates app state, never
changes scheduling, and never throws into the host.
