Problem
A coding CLI in an openab-pty session that has been lent a Mac (reverse attach, #7) can drive a browser only by osascript + screenshot + mouse. Reading a page title means cropping a screenshot at scale: 2 and OCR-ing with the model. Slow, brittle, and the machine has the DOM right there.
The obvious shortcut — the agent talks CDP to Brave on macmini:9222 — is not available by design: the sandbox has no egress (that is the property reverse attach exists to keep; measured in openab-pty#37). Anything browser-shaped must be served from the Mac over the socket the Mac already dialled.
What exists on macmini today
@playwright/mcp 0.0.82 as a LaunchAgent on 127.0.0.1:8794 (poc/pw-mcp/), headed Chromium in the Aqua session, exposed to the tailnet on :8443. Rich tool set: browser_navigate, browser_snapshot (accessibility tree → text), browser_click, browser_type, browser_evaluate, tabs, …
- Brave running with
--remote-debugging-port=9222 (user's own browser, own profile/logins).
- The reverse-attach socket carries plain MCP JSON-RPC and
MCPServer already scopes tools per connection (ToolProfile).
Options
|
A. Relay pw-mcp through instance-mcp |
B. Native browser_* tools over CDP to Brave :9222 |
C. AppleScript only (today) |
| What the agent gets |
Playwright MCP's full tool set, namespaced browser_*, appearing in tools/list under the sandbox profile |
a small set we write: browser_open, browser_eval, browser_text(selector), browser_tabs |
osascript → execute active tab javascript (needs Allow JavaScript from Apple Events once) |
| Browser |
Playwright's Chromium, separate profile (no user logins unless set up) |
the user's Brave, with their logins |
any Chromium via AppleScript |
| Code |
instance-mcp: an MCP client to 127.0.0.1:8794, merge its tools/list into the scoped server, forward tools/call with a prefix; per-profile allowlist (sandbox gets snapshot/navigate/click/type/evaluate; drop browser_install, file chooser, etc.) |
CDP WebSocket client in Swift, target discovery via /json, Runtime.evaluate, Page.navigate |
none |
| Risk |
Playwright's tool surface is large; needs review of what sandbox may call. Two processes to keep alive |
CDP gives full control of the user's logged-in browser — owner profile only, or per-site confirmation |
JS-from-Apple-Events is a global Brave setting |
Proposal
A first, because it is mostly plumbing and the tool set is already good: instance-mcp gains an "upstream MCP" concept — one or more loopback MCP servers whose tools are merged into the served list under a prefix, subject to the connection's ToolProfile. pw-mcp is the first upstream. The sandbox profile allows the read/navigate/interact subset; owner gets everything. Snapshot-based reading (browser_snapshot) answers "what is the first video's title" as text in one call.
B later if driving the user's own Brave (with logins) is wanted — gated to owner, or to a Connect approval tap per site.
C is documented as the zero-code path in the meantime.
Acceptance
- From a lent session (sandbox),
tools/list shows browser_navigate, browser_snapshot, browser_click, browser_type, browser_evaluate and not browser_install/file-chooser tools.
browser_navigate https://www.youtube.com/@AdmonGoldTV/videos then browser_snapshot returns the first video title as text; no screenshot involved.
- The browser window is visible on the Mac's desktop (Connect's Screens pane shows it).
- pw-mcp down → the
browser_* tools are absent from tools/list and instance_status says so; nothing else breaks.
- Sandbox still has no
exec*; the upstream's tools are filtered by the same profile mechanism.
Refs: openabdev/openab#1544, #1 (sandbox adapter), openab-pty#37.
Problem
A coding CLI in an
openab-ptysession that has been lent a Mac (reverse attach, #7) can drive a browser only byosascript+screenshot+mouse. Reading a page title means cropping a screenshot atscale: 2and OCR-ing with the model. Slow, brittle, and the machine has the DOM right there.The obvious shortcut — the agent talks CDP to Brave on
macmini:9222— is not available by design: the sandbox has no egress (that is the property reverse attach exists to keep; measured in openab-pty#37). Anything browser-shaped must be served from the Mac over the socket the Mac already dialled.What exists on macmini today
@playwright/mcp0.0.82 as a LaunchAgent on127.0.0.1:8794(poc/pw-mcp/), headed Chromium in the Aqua session, exposed to the tailnet on:8443. Rich tool set:browser_navigate,browser_snapshot(accessibility tree → text),browser_click,browser_type,browser_evaluate, tabs, …--remote-debugging-port=9222(user's own browser, own profile/logins).MCPServeralready scopes tools per connection (ToolProfile).Options
browser_*tools over CDP to Brave :9222browser_*, appearing intools/listunder the sandbox profilebrowser_open,browser_eval,browser_text(selector),browser_tabsosascript→execute active tab javascript(needs Allow JavaScript from Apple Events once)127.0.0.1:8794, merge itstools/listinto the scoped server, forwardtools/callwith a prefix; per-profile allowlist (sandbox gets snapshot/navigate/click/type/evaluate; dropbrowser_install, file chooser, etc.)/json,Runtime.evaluate,Page.navigateownerprofile only, or per-site confirmationProposal
A first, because it is mostly plumbing and the tool set is already good: instance-mcp gains an "upstream MCP" concept — one or more loopback MCP servers whose tools are merged into the served list under a prefix, subject to the connection's
ToolProfile. pw-mcp is the first upstream. The sandbox profile allows the read/navigate/interact subset;ownergets everything. Snapshot-based reading (browser_snapshot) answers "what is the first video's title" as text in one call.B later if driving the user's own Brave (with logins) is wanted — gated to
owner, or to a Connect approval tap per site.C is documented as the zero-code path in the meantime.
Acceptance
tools/listshowsbrowser_navigate,browser_snapshot,browser_click,browser_type,browser_evaluateand notbrowser_install/file-chooser tools.browser_navigate https://www.youtube.com/@AdmonGoldTV/videosthenbrowser_snapshotreturns the first video title as text; no screenshot involved.browser_*tools are absent fromtools/listandinstance_statussays so; nothing else breaks.exec*; the upstream's tools are filtered by the same profile mechanism.Refs: openabdev/openab#1544, #1 (sandbox adapter), openab-pty#37.