Browser and MCP
A browser column per terminal tab, and the MCP server that lets the agent in that tab drive it.
A browser beside the terminal, so a dev server’s page, its console and the
agent driving it are in the same window as the code. It is the system’s
WebKit — a WKWebView per page, nothing bundled.
⇧⌘B opens and closes the column, as does the globe in the title
bar and View ▸ Browser. Settings ▸ Browser ▸ A browser beside the
terminal (browser.enabled, on by default) turns the whole thing off: no
column, and links open in your own browser instead.
A column per terminal tab
Each terminal tab has its own browser with its own pages, shown as a tab strip under the toolbar. The column shows the selected terminal tab’s browser; switching tabs switches what the browser shows.
A background tab’s pages are parked in an off-screen window rather than suspended, so they keep running, timers keep firing, and an agent’s screenshot of a page in a background tab is not blank.
target=_blank and window.open open a new page in the same strip, built
so the opener keeps its handle on it.
Keys while the browser has the keyboard
| Key | What it does |
|---|---|
| ⌘T | New page, focusing the address bar |
| ⌘W | Close the page |
| ⌘L | Focus the address bar |
| ⌘R | Reload |
| ⌘[ ⌘] | Back, forward |
| ⌃⇥ ⌃⇧⇥ | Next, previous page, wrapping |
| ⌘1…⌘9 | Go to page N — ⌘9 is the last page |
In the address bar, ↩ navigates and hands focus to the page; ⎋ puts the current URL back and hands focus to the page.
The address bar takes more than URLs. :3000 becomes
http://localhost:3000, a bare host gets a scheme, and anything that is not
host-shaped becomes a DuckDuckGo search.
Storage, and the Web Inspector
Cookies and storage use WebKit’s default data store, so they persist and are shared by every page in every tab. (An isolated end-to-end run gets a non-persistent store, so tests never touch your browsing data.)
The hammer in the toolbar opens the Web Inspector; right-clicking a page offers Inspect Element. Developer extras are enabled for these views, so the inspector is the real one.
The console strip
An injected script reports every console.log, info, warn, error and
debug call, plus uncaught errors and unhandled promise rejections. The
strip across the bottom of the column counts them — “✕ 3”, “⚠ 1”, or
“12 logged” — and clicking it opens a 160 pt log panel. A trash button
clears it. Up to 500 messages are kept per page, each truncated at 4000
characters, and the buffer is cleared when the page navigates.
Reload on save
Settings ▸ Browser ▸ Reload the page when a file is saved
(browser.reloadOnSave, off by default) reloads a local page when you
save in the editor, or when the checkout’s files change under an agent (the
latter debounced, so a burst of edits is one reload). It is for a server
without hot reload; with one, leave it off.
Where a link opens
Settings ▸ Browser ▸ Links clicked in the terminal open
(browser.openLinks):
| Value | Behaviour |
|---|---|
local (default) |
Here when the address is on this machine, else in your own browser |
all |
Here, always |
none |
In your own browser, always |
“On this machine” means localhost, 127.0.0.1, 0.0.0.0, ::1, the
.localhost, .local and .test suffixes, and the private IPv4 ranges
(10/8, 127/8, 192.168/16, 172.16–172.31). The same policy applies to a
link ⌘-clicked in the terminal, a port opened from Tab Info, and a
port pill in a pane header. Anything that is not a web URL — mailto:,
tel:, an app scheme — always goes to the system.
With no page open, the column offers the tab’s own listening ports as buttons, labelled with the port and the process holding it.
Ask an agent about the page
The ✦ button sends the page to an agent the same way ⌘L sends a selection: its title, its URL, its console errors and a screenshot written to a temporary file. The sheet is the same one, with an extra target for a new agent tab in the current folder. See Ask an agent.
The MCP server
Claude Code started from Overterm can drive its own tab’s browser. The mechanism is an MCP server Overterm runs itself.
| Transport | Streamable HTTP — JSON-RPC over HTTP POST, JSON answers |
| Bound to | 127.0.0.1 only, on a random port |
| Authentication | Authorization: Bearer <token>; a fresh random token per launch. Without it, 401 |
| Path | one per pane: /mcp/<the pane's OVERTERM_TAB_ID> |
| Server name | overterm-browser |
The per-pane path is the whole point: an agent reaches the browser of the tab it is running in, and no other.
Each pane gets OVERTERM_TAB_ID in its environment, and a config file
written for it at
~/Library/Application Support/Overterm/mcp/<tab id>.json, whose path is
exported as OVERTERM_MCP_CONFIG:
{
"mcpServers": {
"overterm-browser": {
"type": "http",
"url": "http://127.0.0.1:<port>/mcp/<tab id>",
"headers": { "Authorization": "Bearer <token>" }
}
}
}
The file is written with permissions 0600 — the token is a key to the
browser, and it is yours alone. The mcp directory is emptied when the
server starts, and a pane’s config is deleted when its tab closes.
Overterm then starts Claude with that config:
claude --mcp-config "$OVERTERM_MCP_CONFIG"
Nothing is added to Codex’s command line, and nothing is written into your own Claude configuration.
The tools
Thirteen, named so they read in a tool list:
browser_navigate · browser_snapshot · browser_click ·
browser_type · browser_screenshot · browser_console ·
browser_evaluate · browser_back · browser_reload ·
browser_tabs · browser_tab_new · browser_tab_select ·
browser_tab_close
A snapshot returns the page’s text and its controls, each with a short ref
(e1, e2…) that the click and type tools take. Refs are only valid until
the next snapshot, and the error message says so. After a click, a type, a
back or a reload the server waits for the page to settle and returns a fresh
snapshot, so the agent does not have to ask twice. A screenshot comes back as
a PNG.
Turning it off
Settings ▸ Browser ▸ Agents can use the browser
(browser.agentControl, on by default) is the switch. Off, the server is
never started, no config file is written, OVERTERM_MCP_CONFIG is not in any
pane’s environment, and --mcp-config is not added to claude. The browser
column itself is unaffected.
See Privacy for what this does and does not expose.