Skip to content

Latest commit

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Broxy Worker

中文

Broxy backend service built on Cloudflare Worker + Durable Objects. Provides WebSocket bridging, REST API proxy, and MCP (Model Context Protocol) support to expose browser capabilities as callable API services.

Features

  • WebSocket Bridging - Establish persistent connections with browser scripts for real-time communication
  • REST API Proxy - Proxy requests to browsers via /api/{userId}/* endpoint with custom response format support
  • MCP Protocol Support - Implements MCP JSON-RPC 2.0 protocol for AI tool calling
  • Durable Objects - Per-user connection state management with long-lived connections and request queuing
  • Custom Response Format - Support for custom status codes, headers, and binary responses via base64 encoding

Architecture

graph TB
subgraph Client["Clients"]
MCPClient["MCP Client<br/>(AI Tool Calling)"]
APIClient["API Consumer<br/>(HTTP Request)"]
end
subgraph Cloudflare["Cloudflare Worker"]
Worker["Worker Entry<br/>src/index.js"]
DO["Durable Object<br/>BrowserConnection"]
MCPHandler["MCP Handler<br/>src/mcpHandler.js"]
end
subgraph Browser["Browser"]
Ext["Browser Script<br/>(ext/)"]
Handler["Tool Handlers"]
end
MCPClient -->|"POST /mcp/{userId}"| Worker
APIClient -->|"GET/POST /api/{userId}/*"| Worker
Worker -->|"Route"| DO
DO -->|"JSON-RPC"| MCPHandler
DO <-->|"WebSocket"| Ext
Ext -->|"Execute"| Handler
Handler -->|"Result"| Ext
Ext -->|"Response"| DO
DO -->|"Return"| Worker
Worker -->|"Response"| MCPClient
Worker -->|"Response"| APIClient
Loading

API Endpoints

Health Check

GET /health

Response:

{
"status": "ok",
"service": "broxy",
"endpoints": {
"connect": "/connect?id={userId}",
"mcp": "/mcp/{userId}",
"api": "/api/{userId}/{route}"
}
}

WebSocket Connection

GET /connect?id={userId}Upgrade: websocket

Browser scripts establish WebSocket connections through this endpoint.

Connection success message:

{
"type": "connected",
"connectionId": "uuid-xxx",
"message": "Browser bridge connected successfully"
}

Request message (Worker → Browser):

{
"type": "request",
"requestId": "uuid-xxx",
"data": {
"method": "GET",
"path": "/api/route",
"query": {},
"headers": {},
"body": null
}
}

Response message (Browser → Worker):

{
"type": "response",
"requestId": "uuid-xxx",
"result": { "data": "response data" }
}

REST API Proxy

All HTTP methods are supported:

GET|POST|PUT|DELETE /api/{userId}/{route}

Request example:

curl -X POST https://your-worker.workers.dev/api/user123/data/fetch \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/api"}'

Success response:

{
"data": {
"result": "browser execution result"
}
}

Custom Response Format

Browser scripts can return custom response format with status code, headers, and body:

{
"status": 201,
"headers": {
"Content-Type": "text/plain",
"X-Custom-Header": "value"
},
"body": "Plain text response"
}

Return binary data (image, PDF, etc.) using base64 encoding:

{
"status": 200,
"headers": {
"Content-Type": "image/png"
},
"body": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
"isBase64": true
}

Example usage - browser script returns an image:

// Browser script handlerasyncfunctionhandleRequest(request){if(request.path==='/screenshot'){constcanvas=document.createElement('canvas');// ... capture screenshotconstdataUrl=canvas.toDataURL('image/png');constbase64=dataUrl.split(',')[1];return{status: 200,headers: {'Content-Type': 'image/png'},body: base64,isBase64: true};}}

Error response (browser not connected):

{
"error": "Browser not connected",
"userId": "user123",
"hint": "Browser script may not be running or userId is invalid"
}

Error response (timeout):

{
"error": "timeout",
"userId": "user123",
"details": "Browser did not respond within 30000ms"
}

MCP JSON-RPC Endpoint

POST /mcp/{userId}Content-Type: application/json

Initialize request:

{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {
"name": "my-client",
"version": "1.0.0"
}
}
}

Initialize response:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-03-26",
"capabilities": {
"tools": {},
"resources": {},
"prompts": {}
},
"serverInfo": {
"name": "Broxy MCP Server",
"version": "1.0.0"
}
}
}

List tools:

{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}

Tools list response example:

{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "fetch_page",
"description": "Fetch page content",
"inputSchema": {
"type": "object",
"properties": {
"url": { "type": "string" }
},
"required": ["url"]
}
}
]
}
}

Call tool:

{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "fetch_page",
"arguments": {
"url": "https://example.com"
}
}
}

Tool call response:

{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "page content..."
}
]
}
}

Local Development

npx wrangler dev

Development server starts at http://localhost:8787 by default.

Deployment

npx wrangler deploy

After successful deployment, the Worker URL will be output, e.g., https://broxy.your-subdomain.workers.dev.

Configuration

wrangler.toml configuration:

name = "broxy"# Worker namemain = "src/index.js"# Entry filecompatibility_date = "2024-01-01"# Compatibility date# Durable Objects binding
[[durable_objects.bindings]]
name = "BROWSER_CONNECTIONS"# Binding name (referenced in code)class_name = "BrowserConnection"# Durable Object class name# Migration config (required for first deployment)
[[migrations]]
tag = "v1"new_sqlite_classes = ["BrowserConnection"]
# Environment variables
[vars]
DEFAULT_TIMEOUT = "30000"# Request timeout (milliseconds)

Environment Variables

VariableDefaultDescription
DEFAULT_TIMEOUT30000Browser request timeout (milliseconds)

Directory Structure

worker/
├── src/
│ ├── index.js # Main entry, route dispatching
│ ├── durableObject.js # Durable Object, browser connection management
│ └── mcpHandler.js # MCP JSON-RPC protocol handler
└── wrangler.toml # Cloudflare Worker configuration

Related Projects

ProjectDescription
extBrowser extension/Tampermonkey script
ext-uiExtension UI (React + TypeScript)
wwwStatic landing page

License

MIT

Usage Examples

Complete Browser Script Example

// Tampermonkey/extension scriptconstWS_URL='wss://your-worker.workers.dev/connect?id=your-user-id';letws;functionconnect(){ws=newWebSocket(WS_URL);ws.onopen=()=>console.log('Connected to Broxy');ws.onmessage=async(event)=>{constmsg=JSON.parse(event.data);if(msg.type==='request'){constresult=awaithandleRequest(msg.data);ws.send(JSON.stringify({type: 'response',requestId: msg.requestId,
result
}));}};ws.onclose=()=>setTimeout(connect,3000);}asyncfunctionhandleRequest(req){// Handle different routesif(req.path==='/screenshot'){returnawaitcaptureScreenshot();}if(req.path==='/fetch'){returnawaitfetchData(req.body.url);}// Default: return data as-isreturn{path: req.path,method: req.method};}asyncfunctioncaptureScreenshot(){constcanvas=document.createElement('canvas');canvas.width=window.innerWidth;canvas.height=window.innerHeight;constctx=canvas.getContext('2d');ctx.drawImage(document.body,0,0);constdataUrl=canvas.toDataURL('image/png');constbase64=dataUrl.split(',')[1];return{status: 200,headers: {'Content-Type': 'image/png'},body: base64,isBase64: true};}connect();

Call from Client

# Get screenshot
curl https://your-worker.workers.dev/api/your-user-id/screenshot --output screenshot.png
# Fetch data
curl -X POST https://your-worker.workers.dev/api/your-user-id/fetch \
-H "Content-Type: application/json" \
-d '{"url": "https://api.example.com/data"}'

About

Broxy backend service built on Cloudflare Worker + Durable Objects. Provides WebSocket bridging, REST API proxy, and MCP (Mo del Context Protocol) support to expose browser capabilities as callable API services.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages