Skip to main content
Glama

MCP Bridge — Dynamic Tool Gateway

A generic bridge between any MCP client and any tool provider via Cloudflare Workers Durable Objects. Each room gets an isolated Durable Object instance. Tool providers connect via WebSocket, MCP clients connect via Streamable HTTP. Tools are registered dynamically and discovered automatically.

How It Works

┌─────────────────┐  WebSocket   ┌──────────────────────┐  HTTP/SSE   ┌──────────────┐
│  Tool Provider  │ ───────────→ │  Cloudflare Worker   │ ──────────→ │  MCP Client  │
│  (Extension,    │              │  (Durable Object)    │             │  (VS Code,   │
│   App, Script)  │  register    │                      │ tools/list  │   Claude,    │
│                 │  tools       │  dynamic registry    │ tools/call  │   Cursor)    │
│  execute        │─────────────→│  + bridge            │───────────→│              │
│  tools          │←─────────────│  forward calls       │←───────────│  AI agent    │
│                 │  callTool    │                      │             │              │
└─────────────────┘              └──────────────────────┘             └──────────────┘

Related MCP server: Remote MCP Server on Cloudflare

Quick Start

1. Deploy

git clone https://github.com/kelvinzer0/mcp-bridge-cf
cd mcp-bridge-cf
npm install
npx wrangler login
npm run deploy

2. Create a Room

curl https://mcp-bridge.<subdomain>.workers.dev/new

Response:

{
  "room": "ab1fe4c7",
  "extension_url": "https://mcp-bridge.<subdomain>.workers.dev/ws/extension?room=ab1fe4c7",
  "mcp_url": "https://mcp-bridge.<subdomain>.workers.dev/mcp?room=ab1fe4c7",
  "health_url": "https://mcp-bridge.<subdomain>.workers.dev/health?room=ab1fe4c7"
}

3. Connect Tool Provider

const { extension_url } = await fetch("https://mcp-bridge.<subdomain>.workers.dev/new").then(r => r.json())
const ws = new WebSocket(extension_url)

// Register tools
ws.send(JSON.stringify({
  type: "registerTools",
  tools: [{ name: "my_tool", description: "...", inputSchema: { ... } }]
}))

// Handle tool calls
ws.onmessage = (event) => {
  const msg = JSON.parse(event.data)
  if (msg.type === "callTool") {
    const result = executeTool(msg.name, msg.params)
    ws.send(JSON.stringify({ type: "toolResult", callId: msg.callId, result }))
  }
}

4. Connect MCP Client

Use the mcp_url from step 2. Setup per client:

OpenCode (opencode.json):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "browser-bridge": {
      "type": "remote",
      "url": "https://mcp-bridge.<subdomain>.workers.dev/mcp?room=ab1fe4c7",
      "enabled": true
    }
  }
}

Claude Desktop — Settings → Connectors → Add remote server URL:

https://mcp-bridge.<subdomain>.workers.dev/mcp?room=ab1fe4c7

Or claude_desktop_config.json:

{
  "mcpServers": {
    "browser-bridge": {
      "command": "npx",
      "args": ["mcp-remote", "https://mcp-bridge.<subdomain>.workers.dev/mcp?room=ab1fe4c7"]
    }
  }
}

Cursor (~/.cursor/mcp.json):

{
  "mcpServers": {
    "browser-bridge": {
      "url": "https://mcp-bridge.<subdomain>.workers.dev/mcp?room=ab1fe4c7"
    }
  }
}

OpenClaw:

openclaw mcp add browser-bridge --url "https://mcp-bridge.<subdomain>.workers.dev/mcp?room=ab1fe4c7"

Or openclaw.json:

{
  "mcp": {
    "servers": {
      "browser-bridge": {
        "transport": "sse",
        "url": "https://mcp-bridge.<subdomain>.workers.dev/mcp?room=ab1fe4c7"
      }
    }
  }
}

Protocol

Tool Provider → Bridge (WebSocket)

Message

Description

{ type: "registerTools", tools: [...] }

Register tools

{ type: "unregisterTools", names: [...] }

Unregister tools

{ type: "toolResult", callId, result }

Return tool result

{ type: "pong" }

Ping response

Bridge → Tool Provider (WebSocket)

Message

Description

{ type: "callTool", callId, name, params }

Execute tool

{ type: "ping" }

Keepalive

MCP Client → Bridge (Streamable HTTP)

Standard MCP protocol on /mcp?room=<id>:

  • POST /mcp?room=<id> — JSON-RPC (initialize, tools/list, tools/call)

  • GET /mcp?room=<id> — SSE stream

Endpoints

Endpoint

Protocol

Description

/new

HTTP GET

Generate new room

/ws/extension?room=<id>

WebSocket

Tool provider connects here

/mcp?room=<id>

Streamable HTTP

MCP client connects here

/health?room=<id>

HTTP GET

Room status + tool list

Example: Browser Extension

See extension-example/ for a Chrome extension that:

  • Connects to a room via WebSocket

  • Detects page context (GitHub, Gmail, Notion, etc.)

  • Registers context-specific tools dynamically

  • Executes tools in the page DOM

Development

npm run dev      # Local dev with wrangler
npm run typecheck

Security

For production use, add OAuth:

import OAuthProvider from "@cloudflare/workers-oauth-provider"

export default new OAuthProvider({
  apiRoute: "/mcp",
  apiHandler: ...,
})

License

MIT

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

  • Telegram bridge for your MCP-compatible agent. Bidirectional, no LLM in our stack.

  • Markdown-first MCP server for Notion API with 8 composite tools and 39 actions.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kelvinzer0/mcp-bridge-cf'

If you have feedback or need assistance with the MCP directory API, please join our Discord server