Skip to content
/ bridge Public

MCP Mesh Bridge Chrome Extension — write connectors from any website for your agents to operate

Notifications You must be signed in to change notification settings

decocms/bridge

Repository files navigation

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 ✅  │    │                 │   │
│  └─────────────┘    └────────┬────────┘    └─────────────────┘   │
│                              │                                    │
└──────────────────────────────┼────────────────────────────────────┘
                               │ WebSocket
                ┌──────────────▼──────────────┐
                │     Chrome Extension        │
                │                             │
                │  • Observes DOM changes     │
                │  • Extracts structured data │
                │  • Injects AI responses     │
                │  • Per-site content scripts │
                └─────────────────────────────┘

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:

{ 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

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 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

// 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

// 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

// 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

"user.message.received" {
  text: string;       // Message content
  source: string;     // "whatsapp", "linkedin", etc.
  chatId?: string;    // Conversation ID
  sender?: { name?: string };
}

Bridge Subscribes To

"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:

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:

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:

import { mysiteDomain } from "./domains/mysite/index.ts";
registerDomain(mysiteDomain);

Step 4: Manifest

Add to extension/manifest.json:

{
  "content_scripts": [
    {
      "matches": ["https://mysite.com/*"],
      "js": ["domains/mysite/content.js"]
    }
  ]
}

Configuration

# 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/
├── server/
│   ├── index.ts          # Entry point
│   ├── websocket.ts      # WebSocket server
│   ├── events.ts         # Event types
│   ├── core/
│   │   ├── protocol.ts   # Frame types
│   │   ├── mesh-client.ts
│   │   └── domain.ts     # Domain interface
│   └── domains/
│       └── whatsapp/     # WhatsApp implementation
├── extension/
│   ├── manifest.json
│   ├── background.js
│   └── domains/
│       └── whatsapp/
│           └── content.js
└── docs/
    └── ARCHITECTURE.md

Development

# Run with hot reload
bun run dev

# Run tests
bun test

# Format code
bun run fmt

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

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

Domains

Domain Status Description
WhatsApp ✅ Ready Self-chat AI interaction
LinkedIn 🔜 Planned Messaging & networking
X/Twitter 🔜 Planned Compose, DMs
Gmail 🔜 Planned Compose, inbox
Custom 📖 Guide Add any site

License

MIT

About

MCP Mesh Bridge Chrome Extension — write connectors from any website for your agents to operate

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published