All notable changes to this project are documented here. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Relicensed from MIT to GPL-3.0-or-later.
- Connections are now accepted by a front door built on
snail007/goproxy: its HTTP decoder
classifies each connection (CONNECT, absolute-form proxy request, or a
request for Tether's own endpoints) before
net/httpserves it.
-
TOML config file (
--config,$TETHER_CONFIG, or~/.config/tether/config.tomlwhen present; seedocs/CONFIG.mdandtether.example.toml). Precedence is flag > environment > file > default. It covers binding, auth (including[[auth.tokens]], folding in the policy file), allow/deny lists, console capture, the MCP and remote faces, and adds:[headers](headers Chrome sends from Tether's tabs, and client headers the proxy strips),[[cookies]]seeded into the browser at startup, and[chrome].profile/--chrome-profileto launch a specific profile. -
MCP OAuth (
[mcp.oauth],--mcp-oauth): a built-in OAuth 2.1 authorization server with metadata discovery, dynamic client registration, PKCE and refresh tokens, so OAuth-only MCP clients can connect. The consent page asks for a Tether token and the client acts as it; OAuth tokens open/mcponly.--public-urlsets the issuer. -
--policy-filealso accepts TOML (.toml). -
Tailscale exposure (
[tailscale],--tailscale,--tailscale-publish): listen on this machine's tailnet address, and optionally publish over HTTPS withtailscale serve(tailnet) ortailscale funnel(internet), removed again on shutdown. Uses the installed tailscale CLI; needs a token. -
Docs site and landing page at https://adeelahmad.github.io/Tether/, built from
docs/with MkDocs Material and deployed to GitHub Pages on every push tomain(make docs,make docs-serve). -
Per-token and per-session domain policies (
docs/POLICIES.md): a--policy-filedefines named tokens, each with allow/deny rules, anadminflag and ascriptspermission;--deny-domainsadds a global denylist; tabs carry their own session rules (POST /tether/v1/tabs {"policy": …},GET/PUT /tether/v1/tabs/{id}/policy, WebDrivertether:options.policy). Rules are layered (global ∩ token ∩ owning token ∩ session) and restricted tabs are guarded in the browser via the DevToolsFetchdomain, so redirects, link clicks and page script cannot leave the allowlist. -
Tab ownership: non-admin tokens only see and drive the tabs they opened, get their own per-site default tabs, and cannot adopt existing tabs.
-
GET /tether/v1/whoamireports the calling token and its permissions. -
Per-tab console capture:
console.*calls, uncaught exceptions and browser log entries (Runtime.consoleAPICalled,Runtime.exceptionThrown,Log.entryAdded) are kept in a ring buffer per tab (--console-buffer, default 1000,0disables) and exposed viaGET /tether/v1/tabs/{id}/logs?after=&level=, WebDriverget_log("browser")(/se/log,/log), andcore.Core.Logsfor upcoming faces. -
Tab-session core: one session per real Chrome tab, resolved by
X-Tether-Tab-IDheader →tether_tabcookie → one default tab per registrable domain (Public Suffix List). Idle timeout, explicit close, and a410 tab_goneerror for dead tabs. Existing tabs can be adopted by ID. -
HTTP/HTTPS forward proxy. Requests are replayed inside the tab:
GET/HEADnavigate and return the rendered DOM (or raw bytes withX-Tether-Mode: raw); other methods run as same-originfetch()with the browser's cookies. HTTPS via a local CA (/tether/v1/ca.pem). -
W3C WebDriver endpoints for the common Selenium command set (see
docs/WEBDRIVER.md), sharing the same sessions as the proxy. -
WebDriver: frames (same- and cross-site, nested) and shadow roots (open and closed); alerts, confirms and prompts with
unhandledPromptBehavior; multiple windows (New Window, popups, switching, closing); window rect, maximise, minimise and fullscreen for windows the session owns; file uploads, including Selenium's remote file upload; and Print Page. -
Background tabs get Chrome focus emulation, so real input reaches pages with cross-site iframes promptly.
-
WebDriver Actions API (
POST/DELETE /session/{id}/actions): key, mouse, pen, touch and wheel input as real CDP events, soActionChainshover, drag and drop, double/context click, modifier chords and scrolling work. -
Control API under
/tether/v1/: health, tab list/create/close, and JavaScript evaluation viaRuntime.evaluate. -
Connects to an existing Chrome (
--chrome auto|port|host:port|ws://…|DevToolsActivePort) or launches a dedicated one with a persistent profile (--launch). -
Security defaults: loopback-only bind, refusal to listen publicly without
--tokenor--insecure-allow-public, bearer/basic token auth, a loopback Host/Origin guard against DNS rebinding, a per-session domain allowlist policy seam, and log redaction of tokens and cookies. -
MCP server face at
/mcp(Streamable HTTP; MCP 2025-06-18, 2025-03-26 and 2024-11-05) with 16 browser tools: tabs, navigation, accessibility-style snapshots with stable element refs, click, type, keys, select, scroll, wait, JavaScript, screenshots and in-tabfetch()with the user's cookies. Shares tabs, auth, the loopback guard and--allow-domainswith the other faces;--mcp=falseturns it off. Seedocs/MCP.md. -
tether mcp: a stdio bridge for MCP clients that don't speak HTTP (Claude Desktop, IDEs), local or across a tailnet. -
Screenshots of idle background tabs no longer hang: Tether brings the tab to the front and retries, as ChromeDriver does (WebDriver and MCP).
-
Remote-browser web UI at
/remote/, embedded in the binary: live video of any Chrome tab (CDP screencast, with screenshot keyframes for quiet and background tabs), mouse, wheel, touch, keyboard (IME and mobile keyboards included) and clipboard forwarding, JavaScript dialog relay, address bar, back/forward/reload, open/close tabs, watch-only mode and a phone layout. One screencast per tab is shared by all viewers. With--token, a sign-in page trades the token for anHttpOnly,SameSite=Strict, UI-only cookie. Each token signs in to its own UI session under its own rules and tabs. New flags--no-remoteand--remote-quality. Seedocs/REMOTE.md. -
Sprint Zero: Makefile, golangci-lint, CI (lint → test + coverage → build matrix → govulncheck), CodeQL, Dependabot, GoReleaser (archives, checksums, multi-arch Docker image, Homebrew cask), community docs.