telebrowser
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@telebrowseropen the vendor portal; if it asks for 2FA, hand it to me"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
telebrowser
Real browsers for coding agents that run on a remote, headless box. Agents drive a headful Chromium over CDP through an MCP server; when a site needs a human (sign-in, captcha, 2FA, a passkey prompt), you open the same browser from your own machine, do the step, and hand it back. Each project gets its own persistent profile, so a login made for one project is never reachable from another.
Built for a single-operator homelab: two containers, published only on 127.0.0.1, with the human view behind your own reverse proxy and authentication.
How it fits together
agent (pi, Claude Code, Codex, opencode)
stdio MCP: telebrowser mcp host launcher (bin/telebrowser, Node 22+, no deps)
- resolves the project from the working directory
- derives the project token from a shared secret
- runs chrome-devtools-mcp against ws://127.0.0.1:<port>/t/<token>/devtools/browser
- adds browser_handoff, browser_downloads, browser_info
|
v
telebrowser-gateway sidecar sharing the browser container's network
- the only published port, 127.0.0.1 on the host
- token -> project; proxies /json/* and /devtools/* to that project's Chromium only
- starts browsers on demand, stops them after IDLE_MINUTES without CDP traffic
| run/want/<project> (gateway -> supervisor)
| run/up/<project> (supervisor -> gateway)
v
telebrowser stock lscr.io/linuxserver/chromium (Selkies view on :3000)
- browser/supervisor.sh, run as the s6 service svc-telebrowser: one Chromium per project with
--user-data-dir=/data/projects/<p>/profile, debug port on 127.0.0.1 inside the
container, window named [<p>] (used to raise it), downloads to /data/projects/<p>/downloads
- browser/policies: no sync or sign-in, no password manager, no download promptProjects
The project is the directory name of the main checkout, so every worktree of a repository
shares one browser. A submodule is its own project. Outside a git repository the project is
scratch, which is wiped whenever it stops. TELEBROWSER_PROJECT or --project
overrides it.
Data
data/
desktop/ the container's /config (Selkies and labwc state; no browser profile)
projects/<p>/profile/ Chromium user data: cookies and logins
projects/<p>/downloads/ where downloads land (readable on the host)
run/want, run/up, run/raise gateway/supervisor handshake
run/supervisor.logRelated MCP server: Remote Browser
Security model
Network: the gateway is published on host 127.0.0.1 only. Each Chromium's debug port listens on 127.0.0.1 inside the container's network namespace, so nothing else on the Docker network reaches it except through the gateway. The human view (port 3000) is meant to sit behind a reverse proxy with its own authentication (WireGuard + Authelia in the homelab).
Tokens: a token is
<project>.<HMAC-SHA256(secret, project)>. The gateway serves a token only its own project's browser and never lists other projects. This stops one project's agent, or a page prompt-injecting it, from reaching another project's signed-in sessions through the MCP tools or CDP.Limits: every agent runs as the same Unix user. The secret, every profile directory and the Docker socket are all readable to that user, and Chromium's
basicpassword store gives no real encryption at rest. The tokens prevent accidents and cross-project injection, not a deliberately hostile local process.Profiles are not backed up by design. They hold live session cookies, and signing in again is cheap. A copy of a profile in a backup would be a copy of every login in it.
Launcher
telebrowser mcp | status | start | stop | focus | hold [min] | downloads | ws | http | projectConfiguration: TELEBROWSER_URL, else the first line of ~/.config/telebrowser/url, else
http://127.0.0.1:5858; the secret in
TELEBROWSER_SECRET or ~/.config/telebrowser/secret. MCP client configuration, for
any harness:
{ "telebrowser": { "command": "telebrowser", "args": ["mcp"] } }The pinned chrome-devtools-mcp version is CHROME_DEVTOOLS_MCP in cli/mcp-proxy.js.
Gateway configuration
Variable | Default | |
| required | at least 32 characters, same value as the launcher's |
|
| listen port, inside the shared network namespace |
|
| stop a browser after this long without CDP traffic ( |
|
| host path of |
| the human view URL given to agents | |
|
| Chromium debug ports inside the container |
|
| how long |
Deploying
See the homelab stack (telebrowser/docker-compose.yaml there) for the reference
deployment. The browser container mounts:
Repo path | Container path |
|
|
|
|
|
|
|
|
|
|
Without a GPU, set SELKIES_ENCODER=jpeg,h264enc: software H.264 can leave the viewer on
"waiting for stream". Leave the resolution dynamic so the desktop matches the viewer at full
resolution. Windows share one desktop with no taskbar; telebrowser focus and
browser_handoff raise a project's window with browser/raise-window.py
(wlr-foreign-toplevel-management, since Wayland clients cannot raise themselves and labwc
ignores Chromium's own activation). Chromium keeps its default app_id, so labwc draws no
titlebar of its own.
Set S6_SERVICES_GRACETIME=20000 and a stop_grace_period of about 30 s. On shutdown the
supervisor closes every browser with CDP Browser.close, which commits cookies to disk; a
plain SIGTERM, or losing the system D-Bus first, makes Chromium drop the last ~30 s of
cookie writes, i.e. a fresh sign-in. Create the host data directory as the PUID user
before the first start, or Docker creates it root-owned. The gateway image is published as
ghcr.io/justmytwospence/telebrowser-gateway by pushing a vX.Y.Z tag.
Development
npm test # gateway, launcher and MCP proxy unit tests (node:test, no dependencies)The skill for agents is in skill/telebrowser/SKILL.md. It is installed globally from
the dotfiles, which keep a copy.
This server cannot be deployed
Maintenance
Related MCP Connectors
Cloud browsers for AI agents: get past bot detection, sign in with MFA, run web tasks at scale.
- TabfleetOAuthcom.tabfleet
Launch, inspect, control, and share isolated cloud browsers for your agents.
Remote Linux boxes for coding agents: Docker, a browser, screenshots, logs, human takeover.
Run multi-step tasks in a real Chrome browser: persistent environments, live view, human takeover.
Related MCP Servers
- FlicenseNot gradedqualityNot gradedmaintenanceEnables AI agents to authenticate with websites using a real Chromium browser with anti-detection measures and human-in-the-loop support for captchas and 2FA. Features stealth browsing, human-like interactions, and persistent session storage to automate and resume login workflows.-
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to drive a live, persistent self-hosted Chromium session over MCP, running browser actions via Playwright/CDP, capturing page snapshots, screenshots and videos, and managing uploads and downloads in the same tabs and signed-in accounts a human user can take over at any time.3 npmApache 2.0

lyra-browserofficial
AlicenseBqualityCmaintenanceExposes a headful, collaborative browser over MCP so an agent and a user can share one visible Chromium window: the agent navigates, reads, clicks, types, and fills forms, while the user watches and can take over for passwords, CAPTCHAs, 2FA, and payments, with every action written to an append-only audit trail. It also runs headless under a chat-based harness.29MIT- AlicenseNot gradedqualityAmaintenanceEnables coding agents to control the user's real Chrome or Firefox tabs, with their existing logins, to read pages, click, type, fill forms, take screenshots, inspect network traffic and run JavaScript. It works through a paired browser extension over a local WebSocket connection, so automation happens in the browser the user is actually looking at, including shadow DOM, cross-origin iframes, dialogs and single-page apps.MIT