AI-controlled browser farm on your machine
Simulate multiple real users across 22 device types — test your site like it's launch day.
---
## How It Works
> **You:** Open 3 iPhones and a desktop, navigate to myapp.com, test the signup form on all devices
>
> **Claude Code** creates 4 browsers with device emulation, navigates each to your app, fills in the form, takes screenshots, checks console for errors — all in parallel.
```text
gdd_add_players(3, device="iPhone 15 Pro") → players [1, 2, 3]
gdd_add_players(1, device="Desktop 1080p") → player [4]
gdd_navigate(1, "https://myapp.com") → all 4 browsers open your app
gdd_tap(1, "#signup-btn") → taps signup on iPhone
gdd_screenshot(1) → captures the result
gdd_get_console(1, level="error") → checks for JS errors
```
GDD runs N isolated Chromium instances, each with its own profile, cookies, device emulation, geolocation, and network conditions. It exposes **39 MCP tools** via HTTP on `localhost:9700`.
---
## Install
GDD comes in two flavours. The **Server** is headless — it's just the MCP backend, runs anywhere (including boxes with no display), and is all you need for pure AI automation. The **Desktop app** adds a GUI: a live grid of browser thumbnails you can click into to take over a session by hand. The Server runs on port `9700`, the Desktop app on `9800` — so you can run both side by side.
**Server (headless)** — the MCP backend:
| Platform | Download | Run |
|----------|----------|-----|
| **Linux** | [GDD-Server-Linux.tar.gz](https://github.com/Cap-of-tea/GDD/releases/latest/download/GDD-Server-Linux.tar.gz) | `chmod +x GDD.Headless && ./GDD.Headless` |
| **macOS ARM** | [GDD-Server-macOS-ARM.tar.gz](https://github.com/Cap-of-tea/GDD/releases/latest/download/GDD-Server-macOS-ARM.tar.gz) | `bash Scripts/setup-macos.sh && ./GDD.Headless` |
| **macOS Intel** | [GDD-Server-macOS-Intel.tar.gz](https://github.com/Cap-of-tea/GDD/releases/latest/download/GDD-Server-macOS-Intel.tar.gz) | `bash Scripts/setup-macos.sh && ./GDD.Headless` |
| **Windows** | [GDD-Server-Windows.zip](https://github.com/Cap-of-tea/GDD/releases/latest/download/GDD-Server-Windows.zip) | `.\GDD.Headless.exe` |
| **Docker** | `ghcr.io/cap-of-tea/gdd` | `docker run -p 9700:9700 ghcr.io/cap-of-tea/gdd` |
| **Claude Desktop** | [Win](https://github.com/Cap-of-tea/GDD/releases/latest/download/GDD-Server-Windows.mcpb) / [Mac ARM](https://github.com/Cap-of-tea/GDD/releases/latest/download/GDD-Server-macOS-ARM.mcpb) / [Mac Intel](https://github.com/Cap-of-tea/GDD/releases/latest/download/GDD-Server-macOS-Intel.mcpb) (.mcpb) | Open `.mcpb` file — installs as desktop extension |
**Desktop app (GUI)** — a live grid of browser thumbnails you can click into:
| Platform | Download | Run |
|----------|----------|-----|
| **Windows** | [GDD-Desktop-Windows.zip](https://github.com/Cap-of-tea/GDD/releases/latest/download/GDD-Desktop-Windows.zip) | Extract, run `GDD.exe` ([WebView2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/) required) |
| **Linux** | [GDD-Desktop-Linux.tar.gz](https://github.com/Cap-of-tea/GDD/releases/latest/download/GDD-Desktop-Linux.tar.gz) | `bash Scripts/install-deps.sh && ./GDD.Desktop` |
| **macOS ARM** | [GDD-Desktop-macOS-ARM.tar.gz](https://github.com/Cap-of-tea/GDD/releases/latest/download/GDD-Desktop-macOS-ARM.tar.gz) | `bash Scripts/setup-macos.sh && ./GDD.Desktop` |
| **macOS Intel** | [GDD-Desktop-macOS-Intel.tar.gz](https://github.com/Cap-of-tea/GDD/releases/latest/download/GDD-Desktop-macOS-Intel.tar.gz) | `bash Scripts/setup-macos.sh && ./GDD.Desktop` |
The Windows app uses WebView2; the Linux/macOS app (built with Avalonia) drives real Chromium windows parked off-screen. Self-contained binary, ~70 MB. No .NET installation needed. Chromium downloads automatically on first launch.
**One-liner (Linux):**
```bash
curl -sL https://github.com/Cap-of-tea/GDD/releases/latest/download/GDD-Server-Linux.tar.gz | tar xz && chmod +x GDD.Headless && ./GDD.Headless
```
Docker
```bash
# Run (headless, port 9700)
docker run -p 9700:9700 ghcr.io/cap-of-tea/gdd
# Or build locally
docker build -t gdd .
docker run -p 9700:9700 gdd
```
The Docker image runs in headless mode with all Chromium dependencies pre-installed.
By default, browsers launch in **headed** mode (visible windows). Add `--headless` for CI/CD. Other flags: `--stealth` and `--stealth-max` for anti-bot masking, `--update` to self-update, `--version` and `--help`. The **Configuration** section below lists every flag and environment variable.
---
## Connect to Your AI Client
Add to `.mcp.json` and restart your AI client:
```json
{
"mcpServers": {
"gdd": {
"url": "http://localhost:9700/mcp"
}
}
}
```
That's it. Start GDD, tell Claude or Cursor to test your app.
> **Claude Desktop users:** Download the `.mcpb` file from [Releases](https://github.com/Cap-of-tea/GDD/releases/latest) and open it — GDD installs as a one-click desktop extension. No manual config needed.
Config file locations
| Client | Project config | Global config |
| ------ | -------------- | ------------- |
| Claude Code | `/.mcp.json` | `~/.claude/.mcp.json` |
| Cursor | `/.cursor/mcp.json` | `~/.cursor/mcp.json` |
| VS Code / Windsurf / Antigravity | `/.vscode/mcp.json` | IDE `settings.json` |
Global and project configs are merged — servers from both are available simultaneously. Changes are picked up only when restarting the AI client session.
VS Code-based IDEs (Windsurf, Antigravity, Copilot)
VS Code-based IDEs use a different config format than Claude Code / Cursor.
**Project config** — `.vscode/mcp.json`:
```json
{
"servers": {
"gdd": {
"type": "http",
"url": "http://localhost:9700/mcp"
}
}
}
```
**Global config** — open via `Cmd+Shift+P` → "Open User Settings (JSON)":
```json
{
"mcp": {
"servers": {
"gdd": {
"type": "http",
"url": "http://localhost:9700/mcp"
}
}
}
}
```
Global `settings.json` location: macOS — `~/Library/Application Support//User/settings.json`, Linux — `~/.config//User/settings.json`, Windows — `%APPDATA%//User/settings.json`. Replace `` with your editor name (Code, Windsurf, Antigravity, etc.).
**stdio-proxy** alternative (`.vscode/mcp.json`):
```json
{
"servers": {
"gdd": {
"type": "stdio",
"command": "bash",
"args": ["/absolute/path/to/Scripts/mcp-proxy.sh"]
}
}
}
```
Permissions (Claude Code)
By default, Claude Code asks for confirmation on every MCP tool call. To allow GDD tools without prompts, add to `~/.claude/settings.json`:
```json
{
"permissions": {
"allow": [
"mcp__gdd__*"
]
}
}
```
This single wildcard covers all 39 GDD tools. Restart Claude Code after editing.
Auto-launch via stdio proxy (alternative)
Proxy scripts start GDD automatically when your AI client connects:
**Windows:**
```json
{
"mcpServers": {
"gdd": {
"command": "powershell",
"args": ["-ExecutionPolicy", "Bypass", "-File", "C:/path/to/Scripts/mcp-proxy.ps1"]
}
}
}
```
**Linux / macOS:**
```json
{
"mcpServers": {
"gdd": {
"command": "bash",
"args": ["/path/to/Scripts/mcp-proxy.sh"]
}
}
}
```
Add `"--headless"` to the `args` array for CI/CD.
> **Tip:** On first launch, GDD downloads Chromium (~80 MB). If your AI client times out, run GDD manually first, then reconnect.
Autostart as service (macOS / Linux)
**macOS (launchd):**
```bash
bash Scripts/install-launchd.sh # headed (default)
bash Scripts/install-launchd.sh --headless # for CI/CD
```
Manage: `launchctl list | grep gdd` / `bash Scripts/install-launchd.sh --uninstall`
**Linux (systemd):**
```bash
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/gdd.service << 'EOF'
[Unit]
Description=GDD Multi-Browser Testing Server
[Service]
ExecStart=/path/to/GDD.Headless
WorkingDirectory=/path/to/gdd-directory
Restart=on-failure
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now gdd
```
Direct HTTP (without AI client)
```bash
curl -X POST http://localhost:9700/mcp -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"gdd_add_players","arguments":{"count":1}}}'
```
GDD uses standard JSON-RPC 2.0 — works with `curl`, Python, Node.js, or any HTTP client.
---
## Features
- **Multi-device** — Run N isolated Chromium instances with 22 device presets (phones, tablets, desktops)
- **AI-native** — 39 MCP tools for Claude Code, Cursor, or any MCP-compatible client
- **Cross-platform** — Native GUI with a live video wall on Windows, Linux & macOS, plus a headless server for CI/CD
- **Full interaction** — Navigate, tap, type, press keys and shortcuts, drag, swipe, scroll, hover, handle dialogs, take screenshots
- **Real keyboard** — Typing sends genuine, trusted keystrokes (the full keydown→input chain), so input masks, autocomplete and `maxlength` behave exactly as they do for a real user, and rich-text (`contenteditable`) editors work; `gdd_press` handles single keys and shortcuts like Enter, Tab, Escape and Ctrl+A
- **Physical keyboard layouts** — Keystrokes carry the real `code`/`keyCode` of the emulated locale's keyboard: Russian ЙЦУКЕН puts «а» on the physical `KeyF`, French AZERTY and German QWERTZ remap their keys, dead-key accents and AltGr symbols work. The layout follows `gdd_set_language` automatically (US, RU, DE, FR)
- **Human-like input** — `humanize=true` drives a continuous cursor path (cubic Bézier with easing and micro-jitter) that carries over between clicks, hovers and drags; taps fire a single device-appropriate input (touch *or* mouse), never both
- **Anti-bot stealth** — opt-in `--stealth` masks the usual automation tells (`navigator.webdriver`, etc.); `--stealth-max` adds headless/datacenter evasions (coherent user-agent client hints, a plausible WebGL vendor, realistic device metrics) — on a headless container this halved CreepJS's headless score
- **Proxy support** — Route every browser through an upstream proxy with `GDD_PROXY` (with optional auth)
- **Header rewriting** — `gdd_set_headers` can strip `X-Frame-Options`/CSP `frame-ancestors` to load a site in an iframe, or add/replace response headers
- **Device emulation** — Screen size, DPR, touch, user agent, geolocation, timezone, language
- **Network control** — Simulate 4G, Fast 3G, Slow 3G, or offline per browser
- **Diagnostics** — Console errors, network traffic, performance metrics, push notifications
- **Error beacon** — Every tool response warns about JS errors across all browsers automatically
- **Docker-ready** — Official image on GHCR (`ghcr.io/cap-of-tea/gdd`), listed on the [MCP Registry](https://registry.modelcontextprotocol.io)
- **Self-updating** — Built-in version check and one-command update
---
## MCP Tools (39)
### Player Management
| Tool | Description |
|------|-------------|
| `gdd_add_players` | Add N browser instances with optional device preset |
| `gdd_remove_player` | Remove a browser instance by player ID |
| `gdd_list_windows` | List all active browsers with current state |
### Navigation
| Tool | Description |
|------|-------------|
| `gdd_navigate` | Navigate to a URL |
| `gdd_wait` | Wait for a CSS selector to appear (with timeout) |
| `gdd_reload` | Reload page (`hard=true` bypasses cache) |
| `gdd_back` | Navigate back |
| `gdd_forward` | Navigate forward |
### Interaction
| Tool | Description |
|------|-------------|
| `gdd_tap` | Tap element by CSS selector or coordinates; sends a single device-appropriate input (touch on touch devices, mouse on desktop), never both. `humanize=true` adds a continuous human-like cursor path |
| `gdd_swipe` | Swipe gesture (up/down/left/right) |
| `gdd_drag` | Drag an element to (x, y) or onto another element via real pointer events (drives dnd-kit & HTML5 drag-and-drop) |
| `gdd_scroll` | Scroll page or element |
| `gdd_type` | Type text with real, trusted keystrokes (CDP dispatchKeyEvent — masks, autocomplete and maxlength behave as for a real user; works on contenteditable). Physical key codes follow the emulated layout (US/RU/DE/FR); `humanize=true` adds per-key jitter; `paste=true` inserts in one shot |
| `gdd_press` | Press a single key or shortcut (Enter, Tab, Escape, Arrow keys, F1–F12, or a character) with optional modifiers (Control/Alt/Shift/Meta); character keys follow the emulated layout |
| `gdd_hover` | Hover over element. `humanize=true` adds a continuous human-like cursor path |
| `gdd_select` | Select option from `