Install
$ agentstack add mcp-johnconnornpc-browserland ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Browserland
A web-based terminal desktop that launches, streams, and recovers a fleet of headless shells — and the AI coding agents running inside them.
Point a browser at the broker and you get a full windowed desktop of live terminals: tile them, tab them, split them, and drag them across virtual desktops. Each terminal is a real PTY running on some machine, streamed to the browser over a WebSocket.
The shells keep running even when no browser is attached. Close the tab, come back tomorrow, and the screen heals from a snapshot — exactly where you left it.
The name says it plainly: a whole little desktop — windows, terminals, and your fleet of AI coding agents — living entirely in a browser tab. (webterm is the Python package and module name.)
Browserland also exposes an MCP server, letting LLM harnesses drive the terminals directly — including full-screen TUIs.
What is this?
Browserland is two small programs and a browser:
- Agents (producers) are headless processes that own a real terminal —
pty.openpty on Linux, ConPTY/WinPTY on Windows. An agent runs a command (bash, cmd.exe, an AI coding agent, anything), keeps a ring buffer of recent output, and streams the terminal over a single WebSocket.
- The broker is a small web server. Agents register with it; browsers
connect to it. It relays bytes both ways, serves the desktop UI, and can spawn new agents on demand from a list of pre-approved profiles.
- The browser renders the desktop — a tiling window manager over
xterm.js — and sends your keystrokes back to the PTY.
The wire format is a deliberately small set of JSON frames over one WebSocket, so any producer that speaks them can register with the broker — Browserland's own agent is just the reference implementation.
┌─────────┐ binary ANSI + JSON ┌────────┐ /ws?session= ┌─────────┐
│ agent │ ──────────────────▶ │ broker │ ──────────────────▶ │ browser │
│ (PTY + │ ◀────────────────── │ │ ◀────────────────── │ xterm.js│
│ ConPTY/ │ input/resize/ └────────┘ input/paste/resize └─────────┘
│ openpty)│ snapshot_please
└─────────┘
Because the PTY lives in the agent, not the browser, terminals survive browser reloads and even broker restarts — the agent reconnects with backoff and the browser's attach triggers a snapshot redraw from the ring buffer.
Screenshots
The desktop with tiled and floating terminals
Features
- In-browser tiling window manager (niri-style): floating and tiled
windows, a virtual-desktop pager, and a taskbar — all in the page, no native app.
- Nested tabs and splits: any tile can hold a tab group, and tabs can hold
splits, via a recursive cell model. Build the layout you want by dragging.
- More than terminals: sticky notes, a CodeMirror 6
text editor, a file manager, and a task manager — backed by a sandboxed /file/* API.
- Cross-platform PTY: Linux
pty.openpty; Windows auto-selects ConPTY or
WinPTY (ConPTY when a console window exists for correct Ctrl-C handling, WinPTY for headless processes).
- AI agent fleet: detects the foreground coding agent in each window
(claude / codex / grok / opencode), tracks live OSC title + working directory, and surfaces per-window git status.
- Multi-host: attach the same UI to additional brokers (e.g. another machine
over Tailscale), with per-host status chips in the taskbar.
- Single active-browser lease: exactly one browser drives input at a time,
so two open tabs never fight over the keyboard.
- Opt-in MCP / AI agent access: an MCP client or AI harness can list,
observe, drive, and launch terminals — including live interactive TUIs and the console you're working in — under per-window access modes you control. See [MCP & AI agent access](#mcp--ai-agent-access) below.
- Token auth, no open RCE: one token gates non-loopback access and doubles
as the UI password; launching is profiles-only (the client can never supply a raw command), with a loopback exemption for local use.
MCP & AI agent access
The broker exposes a token-gated /mcp/* HTTP API and ships a stdio MCP server (webterm.mcptool), so any MCP client or AI harness can list, observe, drive, and launch terminals. The agents are just producers; the broker stays the sole authority — every MCP call is gated by the same per-window access modes and the master enable switch.
- Interactive TUIs, as plain text —
read_screenrenders the current
screen of a live terminal by replaying its PTY ring buffer through pyte, so a harness can read full-screen apps (btop, htop, vim, less) — not just line-oriented scrollback — and send_input types into them. Without pyte the read falls back to a dependency-free in-house renderer that still returns a bounded rendered grid (degraded: true is now reserved for a rare last-ditch raw decode).
- The live session you're working in —
list_terminalsenumerates running
sessions (id, title, cwd, agent, kind, cols/rows, mode), so a harness can attach to the exact console a person is using right now, read its state, and (in readwrite) drive it. Sessions persist across browser reloads and broker restarts, so the handle stays valid.
Tools
Each tool maps to a broker endpoint and returns its JSON. Window ids are namespaced ":" strings so one server can front several brokers (see Multi-host below); with a single broker the host is default ("default:12345").
| Tool | Endpoint | Notes | |---|---|---| | mcp_info(host?) | GET /mcp/info | feature flags (allow_launch, default_mode). Omit host → dict keyed by host name | | list_terminals | GET /mcp/terminals | {"terminals":[…], "errors":{host:msg}}: all hosts merged, each terminal's host set to the config name (broker's machine hostname preserved as machine_host) + namespaced id; a down host lands in errors without sinking the rest | | list_profiles(host?) | GET /mcp/profiles | launchable profile names + default. Omit host → dict keyed by host name | | read_screen(id) | POST /mcp/read | screen rendered as a bounded plain-text grid (pyte, or a dependency-free fallback) | | send_input(id, data) | POST /mcp/input | target window must be in readwrite mode; newlines are sent as Enter (CR) so commands run (incl. on PowerShell) | | send_keys(id, keys) | POST /mcp/input | send control/escape keys — ["C-c"], ["Esc"], ["Up","Enter"] — that plain text can't express | | launch_terminal(profile?, cols=80, rows=24, title?, cwd?, host?) | POST /mcp/launch | broker must have allow_launch enabled; host required when multiple hosts are configured |
Multi-host. Pass --hosts (or $BROWSERLAND_MCP_HOSTS) a JSON array of {name, url, token} descriptors to serve N brokers from one server process; every id-taking tool routes on the ":…" prefix. The single --broker-url/--token form is the one-host shorthand (default). See [webterm/mcptool/README.md](webterm/mcptool/README.md) for details.
> The send_input tool maps newlines in data to a carriage return — the > byte a real Enter key sends — so a line submits on PowerShell/PSReadLine (which > treats a bare line-feed as a soft continuation) and on a Unix shell alike. The > raw POST /mcp/input endpoint stays verbatim: drive it directly to send a > literal LF or hand-crafted control/escape bytes.
Safety / enabling
Access is layered and opt-in — nothing is reachable until you turn it on:
- Master enable is off by default; while off, every
/mcp/*call returns
403 mcp_disabled.
- Per-window mode is
off/read/readwrite, with a global
default_mode for new windows. off hides a window entirely; read allows observation; readwrite additionally allows send_input.
allow_launchis a separate gate forlaunch_terminal.- The MCP token is a bearer secret distinct from the browser
auth_token
(the UI password): the broker pins it with WEB_TERMINAL_MCP_TOKEN (or the webterm_mcp.json sidecar), and the MCP client passes the same secret via BROWSERLAND_MCP_TOKEN (as the harness examples below show).
Register with a harness
claude mcp add browserland \
--env BROWSERLAND_MCP_TOKEN=… \
--env BROWSERLAND_MCP_URL=http://127.0.0.1:4445 \
-- python -m webterm.mcptool
Any other stdio MCP client (Hermes, your own, …) registers the same way — point it at the launch command and pass the two env vars:
{
"mcpServers": {
"browserland": {
"command": "python",
"args": ["-m", "webterm.mcptool"],
"env": {
"BROWSERLAND_MCP_TOKEN": "…",
"BROWSERLAND_MCP_URL": "http://127.0.0.1:4445"
}
}
}
}
Or run the server directly, talking to the local broker:
BROWSERLAND_MCP_TOKEN=… python -m webterm.mcptool
BROWSERLAND_MCP_TOKEN=… browserland-mcp --broker-url http://127.0.0.1:4445
For the full HTTP contract, error table, and config sidecar, see [docs/TECHNICAL.md](docs/TECHNICAL.md) and [webterm/mcptool/README.md](webterm/mcptool/README.md).
Quick start
You need Python ≥ 3.9. Install from a checkout:
pip install -e .
Windows
# broker (default 127.0.0.1:4445)
python -m webterm.broker
# an agent running cmd.exe, registered with the local broker
python -m webterm.agent -- cmd.exe
# then open http://127.0.0.1:4445/ and click the session (or "new terminal")
Windows agents also need a PTY backend: pip install -e ".[windows]" (pulls in pywinpty).
Linux
./launchers/run-broker.sh # broker
./launchers/run-agent.sh -- bash -l # agent
The launcher scripts bootstrap a virtualenv with the runtime dependencies on first run. Then open http://127.0.0.1:4445/.
Install & extras
pip install -e . # core: broker + agent
pip install -e ".[windows]" # + pywinpty (Windows PTY backend)
pip install -e ".[pyte]" # + pyte (tier-2 snapshot rendering)
pip install -e ".[procs]" # + psutil (task manager, agent badge, live cwd)
pip install -e ".[mcp]" # + the stdio MCP server (Python ≥ 3.10)
pip install -e ".[dev]" # + pytest for the test suite
psutil (the procs extra) is best-effort: it powers the task-manager process list, the foreground-agent badge, and live-cwd tracking. Without it the agent still runs and still destroys windows — those three views just degrade (empty list / no badge / no cwd).
Mix and match, e.g. pip install -e ".[pyte,mcp,dev]". The mcp extra requires Python ≥ 3.10 (the MCP SDK), while everything else runs on Python ≥ 3.9. See [MCP & AI agent access](#mcp--ai-agent-access) for running the server.
Project layout
| Path | What | |---|---| | webterm/agent/ | Headless producer: PTY backends, output ring buffer, OSC-title sniffer, reconnecting WebSocket client | | webterm/broker/ | Web server: desktop UI (ui.py assembles the served page from ordered *.html/*.css/*.js fragments), /ws relay, producer WS, session list, profiles-only launch | | webterm/mcptool/ | The shipped stdio MCP server wrapping the broker's /mcp/* API | | webterm/protocol.py | The single source of truth for the JSON frame shapes | | launchers/ | venv-bootstrapping run scripts (and systemd units) for both OSes | | tests/ | pytest suite: protocol, snapshots, agent↔broker integration, real-PTY round trips |
Documentation
The full engineering reference lives in [docs/TECHNICAL.md](docs/TECHNICAL.md):
- the complete wire protocol and frame semantics,
- the full auth model (every surface, token precedence, CORS),
- every HTTP endpoint including the MCP HTTP contract and its error table,
- access modes, the MCP config sidecar, and the shipped MCP server, and
- deployment notes (systemd units, multi-host over Tailscale, testing).
License
Released under the MIT License — see [LICENSE](LICENSE).
not the.primeagen@gmail.com but hi :)
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: JohnConnorNPC
- Source: JohnConnorNPC/browserland
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.