Command Palette

Search for a command to run...

mariodelgado/tinybrowse-mcp
Public
wasmer run mariodelgado/tinybrowse-mcp

TinyBrowse

A browser built from scratch in Rust — zero dependencies, complete control.

Based on one-agent-one-browser.

Features

  • Custom HTML/CSS/JS rendering — no WebKit, no Chromium
  • Zero third-party Rust dependencies — pure Rust
  • Cross-platform — macOS, Linux/X11, Windows
  • ES6 JavaScript — arrow functions, template literals, spread operator
  • Pure headless mode — Cairo memory rendering, no X11 required
  • WebSocket automation API — full browser control via JSON-RPC
  • MCP server — Claude Code integration with LLM-powered research
  • Autonomous research — Cerebras LLM driver for web research tasks
  • WASI support — WebAssembly build for portable deployment

Quick Start

# Build everything
cargo build --release

# Run with GUI
./target/release/tinybrowse https://example.com

# Headless screenshot
./target/release/tinybrowse --headless --screenshot out.png https://example.com

# Start automation server (WebSocket on port 9222)
./target/release/tinybrowse --headless --port 9222

MCP Server

TinyBrowse includes a standalone MCP server (tinybrowse-mcp) for AI agent integration.

Build

# Standard build (stdio mode for Claude Code)
cargo build --release -p tinybrowse --bin tinybrowse-mcp

# With HTTP server support (for cloud deployment)
cargo build --release -p tinybrowse --bin tinybrowse-mcp --features http-server

Server Modes

ModeUsageBest For
stdio (default)tinybrowse-mcpClaude Code, local MCP
HTTPtinybrowse-mcp --http --port 8080Docker, VPS, cloud

HTTP Mode Example:

# Start HTTP server
./target/release/tinybrowse-mcp --http --port 8080

# Test with curl
curl -X POST http://localhost:8080 \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Configure Claude Code

Add to ~/.mcp.json:

{
  "mcpServers": {
    "tinybrowse": {
      "command": "/path/to/tinybrowse/rust-engine/target/release/tinybrowse-mcp",
      "args": [],
      "env": {
        "TINYFISH_WS_URL": "ws://localhost:9222",
        "TINYBROWSE_API_KEY": "your-server-api-key",
        "CEREBRAS_API_KEY": "your-cerebras-api-key",
        "MIXEDBREAD_API_KEY": "your-mixedbread-api-key"
      },
      "description": "TinyBrowse - Pure Rust MCP with LLM research capabilities"
    }
  }
}

Environment Variables

VariableDescriptionRequired
TINYBROWSE_API_KEYServer authentication key (prefix: tb_)Optional
CEREBRAS_API_KEYCerebras API key for LLM research (prefix: csk-)For research
MIXEDBREAD_API_KEYMixedBread API for semantic searchOptional
TINYFISH_WS_URLWebSocket URL for browserDefault: ws://localhost:9222

Generate API Keys

# Create .env.local with new keys
cat > .env.local << 'EOF'
TINYBROWSE_API_KEY=tb_$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9')
CEREBRAS_API_KEY=csk-your-key-from-cerebras
EOF

MCP Tools

ToolDescription
search_onlySearch web, return URLs only
searchSearch and browse top result
browseNavigate to URL, get page content
actionClick, type, scroll in browser
pageGet current page state
proxyConfigure proxy settings
sessionsList/manage browser sessions
researchLLM-powered autonomous research

Research Tool

The research tool uses Cerebras LLM (GLM 4.7, ~200 tok/s) to autonomously search and browse the web.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "research",
    "arguments": {
      "task": "What is the population of Tokyo?",
      "max_turns": 8,
      "verbose": true,
      "proxy": "http://user:pass@proxy:8080"
    },
    "api_key": "your-tinybrowse-api-key"
  }
}

Parameters:

ParameterTypeDefaultDescription
taskstringrequiredResearch question or task
max_turnsint100Maximum LLM turns
verboseboolfalseEnable detailed console logging
proxystringnullProxy URL for all requests

Verbose Mode

Enable verbose: true to see detailed console output:

╔══════════════════════════════════════════════════════════════╗
║  TINYBROWSE RESEARCH - VERBOSE MODE                         ║
╚══════════════════════════════════════════════════════════════╝
[CONFIG] max_turns=8, proxy=None
[TASK] What is the population of Tokyo?
────────────────────────────────────────────────────────────
[TOOL CALL] search → population of Tokyo
  [RESULT 1] Tokyo Population 2026 - https://worldpopulationreview.com/...
  [RESULT 2] Tokyo - Wikipedia - https://en.wikipedia.org/wiki/Tokyo
[TOOL RESULT] 5 results returned
[LLM] model=zai-glm-4.7 tokens=733 time=322ms speed=189 tok/s
────────────────────────────────────────────────────────────
╔══════════════════════════════════════════════════════════════╗
║  RESEARCH COMPLETE                                          ║
╚══════════════════════════════════════════════════════════════╝
[STATS] time=9918ms
[STATS] total_tokens=6532
[STATS] tool_calls=7
[STATS] pages_browsed=3

Proxy Support

All browser tools support proxy configuration:

{
  "name": "browse",
  "arguments": {
    "url": "https://example.com",
    "proxy": "socks5://user:pass@proxy:1080"
  }
}

Supported formats:

  • http://host:port
  • http://user:pass@host:port
  • socks5://host:port

Testing

# Load environment
source .env.local

# Test tools list
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | \
  ./target/release/tinybrowse-mcp

# Test search
printf '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_only","arguments":{"query":"Rust WebAssembly"},"api_key":"%s"}}' "$TINYBROWSE_API_KEY" | \
  CEREBRAS_API_KEY="$CEREBRAS_API_KEY" ./target/release/tinybrowse-mcp

# Test research with verbose
printf '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"research","arguments":{"task":"What is the capital of France?","max_turns":5,"verbose":true},"api_key":"%s"}}' "$TINYBROWSE_API_KEY" | \
  CEREBRAS_API_KEY="$CEREBRAS_API_KEY" ./target/release/tinybrowse-mcp

WASI Build

Build for WebAssembly (WASI) for portable deployment:

# Install target
rustup target add wasm32-wasip1

# Build (use rustup's cargo, not Homebrew)
rustup run stable cargo build --release \
  --target wasm32-wasip1 \
  --no-default-features \
  --features wasi \
  -p tinybrowse \
  --bin tinybrowse-mcp

# Run locally with Wasmer
wasmer run ./target/wasm32-wasip1/release/tinybrowse-mcp.wasm

Note: WASI build works for MCP protocol but HTTP networking requires native build or Wasmer Edge with networking enabled.

Wasmer Deployment

# Login to Wasmer
wasmer login <your-token>

# Create app.yaml
cat > app.yaml << EOF
kind: wasmer.io/App.v0
name: tinybrowse-mcp
owner: your-username
package: .
env:
  CEREBRAS_API_KEY: "your-key"
  TINYBROWSE_API_KEY: "your-key"
EOF

# Deploy
mkdir -p data tmp  # Required directories
wasmer deploy --publish-package

Docker (Headless)

Run in Docker without any X11 requirements:

# Build
docker build -t tinybrowse .

# Run headless with WebSocket API
docker run -d -p 9222:9222 tinybrowse --headless --port 9222

# Run MCP server with environment
docker run -i \
  -e CEREBRAS_API_KEY=your-key \
  -e TINYBROWSE_API_KEY=your-key \
  tinybrowse-mcp

Docker Compose

docker compose up -d
docker compose ps  # Should show "Up", not "Restarting"

WebSocket Automation API

When running with --port 9222, TinyBrowse exposes a WebSocket automation API.

Connect

const ws = new WebSocket('ws://localhost:9222');

Commands

Navigate:

{"id": 1, "method": "navigate", "params": {"url": "https://example.com"}}

Get page title:

{"id": 2, "method": "getTitle"}

Take screenshot:

{"id": 3, "method": "screenshot", "params": {"path": "/tmp/screenshot.png"}}

Get elements:

{"id": 4, "method": "getElements"}

Click element:

{"id": 5, "method": "click", "params": {"x": 100, "y": 200}}

Type text:

{"id": 6, "method": "type", "params": {"text": "hello world"}}

Set proxy:

{"id": 7, "method": "setProxy", "params": {"url": "http://proxy:8080"}}

Example with websocat

# Install websocat
brew install websocat  # macOS
# or: cargo install websocat

# Connect and send commands
echo '{"id":1,"method":"navigate","params":{"url":"https://example.com"}}' | websocat ws://localhost:9222

# Interactive mode
websocat ws://localhost:9222
{"id":1,"method":"navigate","params":{"url":"https://example.com"}}
{"id":2,"method":"getTitle"}
{"id":3,"method":"screenshot","params":{"path":"/tmp/test.png"}}

Building

Release Build

cargo build --release

Individual Binaries

# Browser GUI
cargo build --release -p tinybrowse --bin tinybrowse

# MCP server
cargo build --release -p tinybrowse --bin tinybrowse-mcp

# WASI build
rustup run stable cargo build --release \
  --target wasm32-wasip1 \
  --no-default-features --features wasi \
  -p tinybrowse --bin tinybrowse-mcp

System Dependencies

macOS

System frameworks only (CoreGraphics/CoreText/ImageIO) — no extra installs.

Linux/X11

For GUI mode:

# Ubuntu/Debian
sudo apt-get install -y libx11-dev libxft-dev libcairo2-dev librsvg2-dev \
    libcurl4-openssl-dev libpng-dev libjpeg-turbo8-dev libwebp-dev

# Arch
sudo pacman -S --needed libx11 libxft cairo librsvg curl libpng libjpeg-turbo libwebp

For headless mode: Only Cairo is required — no X11 needed:

# Ubuntu/Debian
sudo apt-get install -y libcairo2-dev librsvg2-dev libpng-dev

# Arch
sudo pacman -S --needed cairo librsvg libpng

Windows

WinHTTP, WIC, Direct2D/DirectWrite — built into Windows 10/11.

Command Line Arguments

ArgumentDescription
<target>Path to HTML file or http(s):// URL
--screenshot <path>Write PNG screenshot and exit
--headlessDon't create a window (pure Cairo rendering on Linux)
--port <port>Start WebSocket automation server
--width <px>Viewport width (default: 1024)
--height <px>Viewport height (default: 768)

Environment:

  • OAB_SCALE — Override DPI scale factor

Tests

cargo test

# Linux headless (for GUI tests)
xvfb-run -a cargo test

Architecture

tinybrowse/
├── crates/
│   └── tinybrowse/
│       ├── bin/
│       │   └── tinybrowse-mcp.rs  # MCP server with LLM research
│       ├── platform/
│       │   ├── macos/     # CoreGraphics rendering
│       │   ├── x11/       # Cairo/X11 rendering + pure headless
│       │   └── windows/   # Direct2D rendering
│       ├── html/          # HTML parser
│       ├── css/           # CSS parser & cascade
│       ├── js/            # ES6 JavaScript engine
│       ├── render/        # Layout & paint
│       ├── llm.rs         # Cerebras LLM driver
│       ├── http_client.rs # Cross-platform HTTP (native + WASI)
│       └── search.rs      # Web search (MixedBread + DuckDuckGo)
├── wasmer.toml            # WASI deployment config
├── app.yaml               # Wasmer Edge config (gitignored)
└── docker-compose.yml     # Container orchestration

Security

  • API Key Validation: Server validates key format on startup
  • Client Authentication: Requests require api_key in params when TINYBROWSE_API_KEY is set
  • Key Prefixes: tb_ for TinyBrowse, csk- for Cerebras

License

MIT

Lightweight browser MCP server for AI agents - WCGI edition