Skip to content

Repository files navigation

Tabduct

Give your CLI coding agent a handle on the real browser you're already using — the tabs you're logged into, not a throwaway sandbox.

CI license manifest node local protocol

Tabduct is a tiny, local, agent-agnostic bridge. It exposes your already-open, already-logged-in browser tabs to any agent that speaks the Model Context Protocol (MCP) — Claude Code today; Kilo, OpenCode, Cursor, and anything MCP-capable tomorrow.

No built-in chat. No embedded LLM. No vector DB. No telemetry. No native modules. It does exactly one thing: hand your agent the tab you point it at — under your consent, on your machine only.

Tabduct — Share Current Tab / Share Everything    Tabduct — Settings: connection, origin filter, sharing defaults

   CLI agent (Claude Code / Kilo / OpenCode / …)
        │  MCP  (streamable HTTP, 127.0.0.1)         ← standard, language-neutral
        ▼
   Tabduct host   (Node · Python · .NET — pick one)  ← implements /protocol
        │  Chrome Native Messaging (stdio)           ← Tabduct wire protocol
        ▼
   Tabduct extension  (MV3 background service worker) ← the one shared impl
        │  chrome.tabs / chrome.scripting
        ▼
   Your live browser tab (cookies, sessions, DOM)

Why Tabduct

  • Your real session. The agent works with your logged-in tabs — no re-login, no captchas, no throwaway profile.
  • Local-only & private. Binds 127.0.0.1, guarded by a per-session bearer token. Nothing ever leaves your machine — no server, no telemetry, no external calls.
  • You're always in control. Default-deny consent: share one tab or everything, block- or allow-list origins, read-only mode, auto-expiry, and a visible "⚡" group of shared tabs you can drag in and out.
  • Agent- and language-agnostic. MCP to the north, a tiny documented wire protocol to the south. One extension is the fixed point; every host is a thin adapter.
  • Minimal & auditable. Reference host ~1–1.5k lines, zero native dependencies.

Quickstart

Runs on macOS, Linux, and Windows, with Chrome, Chromium, Edge, or Brave. Requires Node ≥ 18.

git clone https://github.com/ultrathinker/tabduct.git && cd tabduct
npm install
npm run register        # installs the native-messaging manifest for your OS + browser
                        # other browsers: node hosts/node/bin/tabduct.js register --browser edge|brave|chromium

register writes the manifest to the right place automatically — ~/Library/Application Support/…/NativeMessagingHosts on macOS, ~/.config/…/NativeMessagingHosts on Linux, or an HKCU registry key on Windows (and makes the launcher executable on POSIX). Then:

  1. Open chrome://extensions → enable Developer modeLoad unpacked → select the extension/ folder.
  2. Click the Tabduct toolbar icon → Start (launches the local server; the header dot turns green). Click the dot again to Stop it.
  3. Open Settings (⚙) → copy the MCP endpoint and Authorization token.
  4. Paste them into your agent's MCP config (below) and reload the agent.
  5. Share what the agent may touch: Share Current Tab, or Share Everything. That's it.

Diagnose the host anytime with npm run doctor. In-app help lives under Settings → How it works.

Point your agent at it (MCP)

Hub mode requires the Node host. The "shared hub" below is implemented only in hosts/node/src/hub.js. If you are running the Python or .NET host, skip to the per-instance config and point your agent at the port + token shown in the popup (Settings → MCP endpoint / Authorization).

With the shared hub (on by default when using the Node host), every browser you connect appears behind one stable endpoint with a token that never changes:

{
  "mcpServers": {
    "tabduct": {
      "type": "http",
      "url": "http://127.0.0.1:12311/mcp",
      "headers": { "Authorization": "Bearer PASTE_TOKEN_FROM_SETTINGS" }
    }
  }
}

Reload your agent and it discovers the Tabduct tools below. (Prefer a direct, per-browser endpoint? Turn the hub off in Settings — the popup then shows that browser's own port and token.)

Tools

Tool What it does
list_tabs / get_active_tab Enumerate / get the focused tab — filtered to shared tabs only
get_page_content / get_dom_snapshot Read a shared tab's text/HTML, or a compact outline of its interactive elements
screenshot Capture the visible tab (returned as an MCP image)
click / type Click an element / type into a field, by CSS selector
wait_for Wait for a selector, URL fragment, or load state (bounded)
navigate Point a shared tab at a URL
open_tab / activate_tab / close_tab Tab management
get_console_logs Read the tab's console output (plus uncaught errors, in CDP mode)
execute_script Run arbitrary JS in a shared tab — read and modify the page

Most tools — including click / type / wait_for / get_dom_snapshot — run as injected functions, so they work even on strict-CSP sites (GitHub, banks, SaaS). Only arbitrary-string execute_script is blocked by a page's CSP; for that, opt into CDP mode (see below). Unshared tabs are completely invisible — the agent can't even read their title.

Security & consent

The endpoint is token-authenticated — not merely bound to localhost (which every local process shares). On Start the extension mints a bearer token; the host requires Authorization: Bearer <token> on every request, rejects Origin-bearing requests, and pins the Host header (DNS-rebinding defense).

Consent is default-deny and enforced inside the extension (the sole path to the browser). All of these are in the popup:

  • Origin filterBlock mode (listed sites are never shared) or Allow mode (only listed sites can ever be shared). Overrides every sharing mode.
  • Lock shared tabs to their domain (default on) — a shared tab that navigates away loses access, so a shared shopping tab can't follow you into your bank.
  • Read-only — the agent may look but never click, type, navigate, run scripts, or open/close tabs.
  • Auto-expire — un-shares everything after a chosen time (5 min … 10 h).
  • Don't auto-share tabs the agent opens (default on).
  • CDP mode (Advanced, opt-in, default off) — lets execute_script bypass a page's CSP via the DevTools Protocol, with an optional "developer mode" that routes all eval through it and full console/error capture. Chrome forbids requesting debugger at runtime, so it's a required permission granted at install — but nothing attaches until you flip this toggle on, and use is still gated by consent (never in read-only). Chrome shows a "being debugged" banner whenever it's actually in use.
  • Sharing lives in session storage → it resets when the browser restarts.

The full trust model and honest limitations are in SECURITY.md — which is also where to report a vulnerability (please don't open a public issue).

Multiple browsers & profiles

This section describes the Node-host hub. The Python and .NET hosts expose one per-instance endpoint each (the port + token shown in the popup) and do not aggregate behind a shared endpoint.

Install Tabduct in each Chrome profile you use (each Google account / profile is separate). Start each; with the hub on they all sit behind the one endpoint, and the agent tells them apart by their Label (auto-named like Chrome-abcd — rename to Work / Personal in Settings).

Two protocols, one extension, many hosts

Tabduct is defined by contracts, not implementations:

  • North (agent ↔ host): MCP. Already standardized; SDKs for Node, Python, .NET. Nothing to invent.
  • South (host ↔ extension): the Tabduct wire protocol. Chrome Native Messaging framing + message schema + tool catalog. Specified once in protocol/ — the single source of truth.
  • The extension is the fixed point (it must be JS): it defines what the browser can do; every host is a thin relay of MCP calls to it (~1k lines in any language — see the per-host counts in docs/ARCHITECTURE.md).
Host Status Hub Notes
hosts/node ✅ reference impl ✅ yes zero native deps, Node ≥ 18, MCP SDK wired, conformance-passing; ships the shared hub facade (hosts/node/src/hub.js)
hosts/python ✅ passes conformance ❌ no official mcp SDK + register (macOS/Linux/Windows); exposes only its per-instance endpoint
hosts/dotnet ✅ passes conformance ❌ no ModelContextProtocol SDK, net10.0 + register; exposes only its per-instance endpoint

Hub is currently a Node-host feature. The shared hub (one stable endpoint behind which every connected browser appears) is implemented only in hosts/node/src/hub.js. The Python and .NET hosts do not read payload.hub and expose only their own per-instance MCP endpoint — point your agent at the port/token shown in the popup. See docs/ROADMAP.md for plans to bring the hub to the other hosts.

New languages need no permission — implement protocol/PROTOCOL.md and pass protocol/conformance/.

Project layout

extension/            MV3 extension (the fixed point): consent, sharing, popup, icons
hosts/node/           reference host — CLI (register/doctor/run/instances/hub) + src/
protocol/             PROTOCOL.md + JSON schemas + conformance runners
docs/                 ARCHITECTURE, DESIGN-consent-and-multibrowser, ROADMAP
scripts/              consent unit tests, icon/key generators

Run the full test suite (pure JS, no browser needed): npm test — consent unit tests + host conformance + hub conformance.

Status

Working reference implementation, pre-1.0. Developed and exercised on Windows; the macOS/Linux code paths are implemented (per-OS manifest install, POSIX file modes, launcher chmod) but deserve a smoke test on each before you lean on them. See docs/ROADMAP.md.

Originality

Tabduct is written from scratch. It reuses no third-party source code — only standard, public interfaces: Chrome's Native Messaging framing (a documented OS transport) and the Model Context Protocol. Nothing here carries a third-party attribution obligation.

License

MIT — see LICENSE.

About

Local, consented bridge from CLI coding agents (MCP) to your real, logged-in Chrome tabs. No chat, no cloud.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages