paniolo browser

One window, two drivers

paniolo browser opens a Chromium window on a dedicated profile that a human and an agent share: you drive with the mouse and keyboard, the agent attaches over the Chrome DevTools Protocol and sees the same DOM, console, and session. The ten browser_* tools ship on the Paniolo MCP server, so from @paniolo/cli 0.5.76 there is nothing extra to install.

Quick start

Launch, drive, hand it back

paniolo browser launch https://example.com

That starts a Chromium-family browser with a dedicated profile at ~/.paniolo-browser, a remote-debugging port on loopback, and --enable-features=WebMCPTesting. A second launch against a running instance reuses it and opens the URL there — racing the same profile is how the debugging flags get silently dropped.

Two knobs when the defaults miss: --port runs a second instance when one browser genuinely is not enough — one port per browser is the unit, there is no multiplexing — and PANIOLO_BROWSER_BIN picks the executable. The search covers Chrome and Edge on Windows, Chrome and Chromium on macOS, and the usual /usr/bin and snap paths on Linux.

paniolo browser tabs # what the human has open paniolo browser teardown # stop the instance, keep the profile

teardown --wipe-profile discards the profile, sign-ins included. Never taskkill /IM chrome.exe — that closes the human's other windows too.

The tools

See the page, then act on it

Four reads and six writes. Reads are never gated; writes ask on real origins — the consent model is below. The catalog entry lives on the MCP server page.

ToolKindWhat it does
browser_tabsreadList open tabs — what the human has in front of them, before acting.
browser_consolereadDrain console output, logs, and failed requests since the last call. The first call subscribes and returns no history.
browser_screenshotreadCapture a tab as a base64 PNG.
browser_webmcp_listreadList the tools the current page declares about itself via WebMCP. Same-origin only.
browser_navigatewritePoint a tab at a URL — it moves a page someone may be using.
browser_clickwriteClick an element as the signed-in user.
browser_fillwriteSet a form field, dispatching the input and change events frameworks listen for.
browser_typewriteType as real keyboard input, for fields that only react to genuine typing.
browser_evalwriteEvaluate JavaScript in a tab and return its value. chrome:// pages are refused.
browser_webmcp_callwriteRun a tool the page declares. Executes site code as the signed-in user.

There is no snapshot-and-click-by-id model. Targets are CSS selectors — browser_eval is how an agent discovers them on an unfamiliar page: list a form's fields and their names before filling anything. There is also no new-tab tool; paniolo browser launch <url> opens a URL in the running instance and browser_navigate moves an existing tab.

Safety

Writes ask, once, on real sites

Every write tool refuses on an origin that is not loopback, file: or about:, returning confirmation_required and naming the origin. The agent shows the human what it is about to do, gets a yes, and retries with confirm: true. Loopback is ungated on purpose — a flag everyone always passes has stopped being a gate, so the friction lands where it matters: a local dev server is free, production asks.

The gate exists because the debug port is session-equivalent access: evaluating an expression against a signed-in production tab is a different act from the same expression against a dev server, and cookies are readable over CDP even when marked httpOnly. That is also why the profile is a boundary rather than a convenience — the browser never attaches to the human's everyday profile, and Chrome ignores the debugging flag on a default profile anyway.

WebMCP

Pages that describe themselves

A page that declares WebMCP tools exposes them through document.modelContext. browser_webmcp_list returns each declared tool's name, description, input schema and annotations; browser_webmcp_call runs one with an input object:

{ "tool": "fill_contact_form", "input": { "name": "Example Person" } }

When a call is gated, the refusal reports what the page claims about the tool — its annotations. That claim is page-supplied data: a page can omit it or lie, so it is shown to help a human decide and never used to decide whether to ask. Fill-type tools are usually safe; submit-type tools send, pay, delete or publish. Sites that gate submission behind a bot check may declare a wait-for-verification tool — use it before the submit tool rather than polling the DOM.

If the list stays empty after the app is ready and a bounded wait, fall back to DOM actions — browser_click, browser_fill, browser_type — for the user's ordinary task. Ordinary sites do not need WebMCP. For the standard on this site's own contact form, see Agent-First.

Pitfalls

The failure modes worth knowing

SymptomWhat is going on
The agent has no browser_* toolsA host problem, not a browser problem. If query works and browser_tabs does not, the host is pre-0.5.76; if neither works, the Paniolo server is not loaded. A responding debug port does not prove otherwise.
Window opens, port closedA launch against a running instance on the same profile forwards to it and drops the new flags. paniolo browser launch reuses the live instance instead of racing it; if flags are still missing, teardown and relaunch.
A normal Chrome window will not answerOpening a URL through the OS default browser hits a different profile with no debug port. Always paniolo browser launch or browser_navigate.
A fill looks applied but submits emptySetting a value without dispatching input and change leaves the framework holding old state. browser_fill dispatches both; driving the DOM through browser_eval does not.
Input vanishedNavigating or relaunching reloads the page and unsent form input is lost — refill after any restart.
Submission silently discardedPages hide honeypot fields for bots to fill and humans to skip. Do not fill them.
Sign-in confusionThe human signs in inside the shared window — signing in on another profile does not authenticate the browser the agent controls. Then verify with browser_tabs and inspect the page.
Learn more

The browser is a surface, not a separate product

The tools are siblings of the CLI commands, served by the same stdio server as retrieval, wiki, and staleness — see MCP server for the transport, the read/write split, and the full 39-tool catalog. For what happens when a page declares its own tools — including the origin trials and the three silent bugs we fixed on our own contact form — read Agent-First.