https://github.com/decocms/bridge
MCP Mesh Bridge Chrome Extension — write connectors from any website for your agents to operate
https://github.com/decocms/bridge
Last synced: about 1 month ago
JSON representation
MCP Mesh Bridge Chrome Extension — write connectors from any website for your agents to operate
- Host: GitHub
- URL: https://github.com/decocms/bridge
- Owner: decocms
- Created: 2026-01-02T02:53:24.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2026-01-10T22:46:41.000Z (6 months ago)
- Last Synced: 2026-01-11T06:53:23.315Z (6 months ago)
- Language: TypeScript
- Size: 244 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# mesh-bridge
**Turn any website into an MCP event stream.**
A Chrome extension that maps DOM events to MCP Event Bus messages. AI agents can subscribe to browser events and publish responses that appear on websites—all running locally on your machine.
```
┌──────────────────────────────────────────────────────────────────┐
│ MCP MESH │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ EVENT BUS │ │
│ │ │ │
│ │ user.message.received ◄── bridge publishes │ │
│ │ agent.response.* ────────► bridge subscribes │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ ▲ │
│ │ │
│ ┌─────────────┐ ┌────────┴────────┐ ┌─────────────────┐ │
│ │ Agents │ │ mesh-bridge │ │ Other MCPs │ │
│ │ │◄───│ │───►│ │ │
│ │ Subscribe │ │ DOM ↔ Events │ │ Can also │ │
│ │ Process │ │ │ │ subscribe/ │ │
│ │ Respond │ │ Domains: │ │ publish │ │
│ │ │ │ • WhatsApp ✅ │ │ │ │
│ │ │ │ • CLI ✅ │ │ │ │
│ └─────────────┘ └────────┬────────┘ └─────────────────┘ │
│ │ │
└──────────────────────────────┼────────────────────────────────────┘
│ WebSocket
┌──────────────────────┼──────────────────────┐
│ │ │
┌───────▼─────────────┐ ┌─────▼──────────────┐
│ Chrome Extension │ │ CLI (terminal) │
│ │ │ │
│ • Observes DOM │ │ • bun dev │
│ • Injects AI text │ │ • Monitor mode │
│ • Per-site scripts │ │ • Auto-reconnect │
└─────────────────────┘ └────────────────────┘
```
## How It Works
1. **Extension** observes DOM events (new messages, clicks, navigation)
2. **Bridge** translates DOM events into Event Bus messages
3. **Agents** (or any MCP) subscribe to events and process them
4. **Responses** flow back through the bridge into the DOM
**The AI never sees the DOM.** It sees structured events like:
```typescript
{ type: "user.message.received", text: "Hello", source: "whatsapp", chatId: "self" }
```
## Quick Start
### 1. Add to Mesh
In MCP Mesh, add a new **Custom Command** connection:
| Field | Value |
|-------|-------|
| Name | `Mesh Bridge` |
| Type | `Custom Command` |
| Command | `bun` |
| Arguments | `run`, `start` |
| Working Directory | `/path/to/mesh-bridge` |
### 2. Install Extension
```bash
cd mesh-bridge
bun install
```
Then in Chrome:
1. Go to `chrome://extensions`
2. Enable **Developer mode**
3. Click **Load unpacked** → select `extension/`
### 3. Open WhatsApp Web
Navigate to [web.whatsapp.com](https://web.whatsapp.com) and open your self-chat ("Message Yourself"). Send a message—the agent will respond!
## The WhatsApp Domain
The WhatsApp domain demonstrates the full pattern:
### DOM → Events
```javascript
// Content script observes new messages
new MutationObserver(() => {
const lastMessage = getLastMessage();
if (isNewUserMessage(lastMessage)) {
socket.send(JSON.stringify({
type: "message",
domain: "whatsapp",
text: lastMessage,
chatId: getChatName()
}));
}
}).observe(messageContainer, { childList: true, subtree: true });
```
### Bridge → Event Bus
```typescript
// Server publishes to Event Bus
await callMeshTool(eventBusId, "EVENT_PUBLISH", {
type: "user.message.received",
data: {
text: message.text,
source: "whatsapp",
chatId: message.chatId
}
});
```
### Event Bus → DOM
```javascript
// Content script receives response
socket.onmessage = (event) => {
const frame = JSON.parse(event.data);
if (frame.type === "send") {
// Inject into WhatsApp input
const input = document.querySelector('[data-testid="conversation-compose-box-input"]');
input.focus();
document.execCommand("insertText", false, frame.text);
document.querySelector('[data-testid="send"]').click();
}
};
```
## Event Types
### Bridge Publishes
```typescript
"user.message.received" {
text: string; // Message content
source: string; // "whatsapp", "linkedin", etc.
chatId?: string; // Conversation ID
sender?: { name?: string };
}
```
### Bridge Subscribes To
```typescript
"agent.response.whatsapp" {
taskId: string;
chatId?: string;
text: string;
imageUrl?: string;
isFinal: boolean;
}
"agent.task.progress" {
taskId: string;
message: string;
}
```
**Any MCP** can subscribe to `user.message.*` or publish `agent.response.*` events.
## Adding a Domain
### Step 1: Content Script
Create `extension/domains/mysite/content.js`:
```javascript
const DOMAIN = "mysite";
let socket = new WebSocket("ws://localhost:9999");
socket.onopen = () => {
socket.send(JSON.stringify({ type: "connect", domain: DOMAIN, url: location.href }));
};
// Observe DOM → publish events
new MutationObserver(() => {
const data = extractFromDOM();
if (data) {
socket.send(JSON.stringify({ type: "message", domain: DOMAIN, ...data }));
}
}).observe(document.body, { childList: true, subtree: true });
// Subscribe to responses → mutate DOM
socket.onmessage = (e) => {
const frame = JSON.parse(e.data);
if (frame.type === "send") {
injectIntoDom(frame.text);
}
};
```
### Step 2: Server Handler
Create `server/domains/mysite/index.ts`:
```typescript
import type { Domain } from "../../core/domain.ts";
export const mysiteDomain: Domain = {
id: "mysite",
name: "My Site",
urlPatterns: [/mysite\.com/],
handleMessage: async (message, ctx) => {
await publishEvent("user.message.received", {
text: message.text,
source: "mysite",
chatId: message.chatId
});
}
};
```
### Step 3: Register
In `server/main.ts`:
```typescript
import { mysiteDomain } from "./domains/mysite/index.ts";
registerDomain(mysiteDomain);
```
### Step 4: Manifest
Add to `extension/manifest.json`:
```json
{
"content_scripts": [
{
"matches": ["https://mysite.com/*"],
"js": ["domains/mysite/content.js"]
}
]
}
```
## Configuration
```bash
# WebSocket port (extension connects here)
WS_PORT=9999
# For standalone mode only
MESH_URL=http://localhost:3000
MESH_API_KEY=your-key
```
## File Structure
```
mesh-bridge/
├── cli/
│ └── index.ts # CLI client (connects to server via WebSocket)
├── server/
│ ├── stdio.ts # STDIO mode (mesh-hosted, starts WebSocket server)
│ ├── index.ts # Auto-detect mode (stdio vs standalone)
│ ├── websocket.ts # WebSocket server
│ ├── events.ts # Event types
│ ├── core/
│ │ ├── protocol.ts # Frame types
│ │ ├── mesh-client.ts
│ │ └── domain.ts # Domain interface
│ └── domains/
│ ├── whatsapp/ # WhatsApp implementation
│ └── cli/ # CLI domain
├── extension/
│ ├── manifest.json
│ ├── background.js
│ └── domains/
│ └── whatsapp/
│ └── content.js
└── docs/
└── ARCHITECTURE.md
```
## Development
```bash
# Start server (STDIO mode)
bun stdio
# CLI client (connects to server)
bun dev
# Run tests
bun test
# Format code
bun run fmt
# Type check
bun run check
```
## Why Event-Driven?
| Approach | Tokens/interaction | Reliability |
|----------|-------------------|-------------|
| Screenshot + Vision | 1000-3000 | Fragile |
| DOM serialization | 2000-10000 | Fragile |
| **Event-based** | **50-100** | **Stable** |
Events are:
- **Small**: Structured data, not HTML noise
- **Stable**: Event types don't change when UI changes
- **Composable**: Any MCP can subscribe/publish
## Recent Updates
### Auto-Recovery from Extension Context Invalidation
Chrome's Manifest V3 suspends service workers after ~30 seconds of inactivity. Previously, this would break the extension when returning to a tab after being away.
**Now:** The content script monitors for context invalidation and automatically reloads the page when detected. No more "Extension context invalidated" errors requiring manual refresh.
### Thread Continuity
The bridge now works seamlessly with Pilot's thread management. Conversations within 5 minutes are treated as the same thread, enabling natural follow-ups like:
- "draft this" → continues from previous research
- "yes" / "continue" → proceeds to next workflow step
- "new thread" → starts fresh
## Privacy
- Runs **locally** on your machine
- Uses **your browser session** (no credential sharing)
- Only processes **self-chat** in WhatsApp (never private conversations)
- **Open source**—audit the code yourself
## Usage
### Starting the Server
The server runs via STDIO mode (for mesh integration) and also starts a WebSocket server for browser extensions:
```bash
bun stdio # Start server (STDIO + WebSocket on port 9999)
bun dev:stdio # Same, with hot reload
```
### CLI Client
The CLI connects to the running server:
```bash
bun dev # Connect to server
bun dev:monitor # Connect with all-events monitoring
```
```
╔════════════════════════════════════════════════════════════╗
║ 🌐 MESH BRIDGE CLI ║
║ Terminal Interface for Mesh Bridge ║
╚════════════════════════════════════════════════════════════╝
✓ Connected (session: cli-local-1736500000)
Domains: whatsapp, cli
you ❯ what's the weather in SF?
07:24:59 → what's the weather in SF?
07:25:01 ⚡ perplexity search
07:25:03 🤖 San Francisco is currently 58°F with fog...
```
### CLI Commands
| Command | Description |
|---------|-------------|
| `/help` | Show help |
| `/new` | Start new thread |
| `/monitor` | Toggle monitor mode (see all events) |
| `/status` | Show connection status |
| `/reconnect` | Force reconnection to server |
| `/quit` | Exit CLI |
### Monitor Mode
With `--monitor` flag or `/monitor` command, CLI shows **all** events from all sources:
```
07:24:55 [wa] → run article research for AI agents # WhatsApp message
07:24:57 [wa] ⚡ perplexity search
07:25:02 [wa] ← Started create-article-research
07:25:10 [cli] → list my tasks # Your CLI message
07:25:11 [cli] ← You have 3 active tasks...
```
## Domains
| Domain | Status | Description |
|--------|--------|-------------|
| WhatsApp | ✅ Ready | Self-chat AI interaction |
| CLI | ✅ Ready | Terminal interface |
| LinkedIn | 🔜 Planned | Messaging & networking |
| X/Twitter | 🔜 Planned | Compose, DMs |
| Gmail | 🔜 Planned | Compose, inbox |
| Custom | 📖 Guide | Add any site |
## License
MIT