Connect Ostler to your MCP client
Configure Ostler as a local MCP browser for your coding agent. Find setup commands, configuration locations and troubleshooting steps.
On this page
Ostler is an MCP server over stdio. Any MCP client can launch it. ostler setup <client> prints the exact config, using this binary's absolute path. That avoids "command not found" when an app's PATH differs from your shell's.
| client | command | result |
|---|---|---|
| Claude Code | ostler setup claude --apply | runs claude mcp add for you |
| Codex | ostler setup codex | prints the block for ~/.codex/config.toml |
| Cursor | ostler setup cursor | prints JSON for ~/.cursor/mcp.json |
| VS Code | ostler setup vscode | prints JSON for .vscode/mcp.json |
| anything else | ostler setup json | generic mcpServers JSON |
Only Claude Code is applied automatically. Other clients' files are never modified: you paste or merge the printed snippet. Extra serve flags go after --:
ostler setup claude --apply -- --lean --tools formsClaude Code#
ostler setup claude --apply
# manual equivalent:
claude mcp add ostler -- ostler serveReconnect with /mcp after installing or rebuilding.
Codex#
ostler setup codexPrints a block for ~/.codex/config.toml. Paste or merge it:
[mcp_servers.ostler]
command = "/absolute/path/to/ostler"
args = ["serve"]Cursor#
ostler setup cursorPrints JSON for ~/.cursor/mcp.json (or .cursor/mcp.json in a project):
{
"mcpServers": {
"ostler": {
"command": "/absolute/path/to/ostler",
"args": ["serve"]
}
}
}VS Code#
Easiest: install the Ostler extension from Open VSX (Cursor, Windsurf and other forks; the VS Code Marketplace listing is not published yet). It registers Ostler as an MCP server, uses an ostler on your PATH or downloads and checks the release once, and adds Ostler: Check setup and Ostler: Sign in to a website. Source: editors/vscode.
Or by hand:
ostler setup vscodePrints JSON for .vscode/mcp.json. VS Code uses a servers key and an explicit transport type:
{
"servers": {
"ostler": {
"type": "stdio",
"command": "/absolute/path/to/ostler",
"args": ["serve"]
}
}
}With uvx or pip (no Rust)#
Any MCP client can launch Ostler from the Python package ostler-mcp (it carries the same binary):
{ "mcpServers": { "ostler": { "command": "uvx", "args": ["--from", "ostler-mcp", "ostler", "serve"] } } }pip install ostler-mcp instead puts the ostler command on your PATH. Use pipx or uv tool install to keep it isolated.
Any other MCP client#
ostler setup jsonprints the common mcpServers shape. The only requirement is that the client starts ostler serve and speaks MCP over stdio. ostler serve should print one ready line on stderr and wait; stdout carries only MCP messages.
Building your own agent in Python? See LangChain, LlamaIndex and AutoGen for tested code. Keep one Ostler session open for the whole task, or cite will not see what read fetched.
A good agent workflow#
For research with citations:
search(or start from known URLs), thenopen_manywith aqueryto read the best passages of up to 10 pages.readwith aqueryto go deeper on one page; followlinksorextracttables and lists.citeevery quote you intend to use. OnlyVERIFIEDquotes go in the answer.evidencebefore answering: it lists the verified citations and the pages that could not be read, which the answer should name as gaps.
A prompt that works: "Research X. Cite every claim with cite; call evidence before answering and list what you could not read."
For reading or testing a page:
navigateopens the page and lists its interactive elements;snapshotreturns the page as text (pass a heading's ref to read one section).lookreturns a screenshot with numbered click targets, which helps when a cookie banner or modal is in the way.click,type,pressandwait_foract on the page;screenshotcaptures the result. Page text arrives fenced as untrusted, so instructions inside a page are data, not commands.
For forms:
navigatereturns the page's interactive elements.form_inspectreturns typed fields and shows what memory knows about this form.form_fillwith{label: value}for what you know; addauto: "required"to fill the rest from memory.form_submit, then read the status: Submitted, Advanced (next step: repeat 2 to 4), or NOT ACCEPTED with the page's validation messages.
ostler inspect <url> prints the form model as JSON for debugging.
Control what the agent sees and can do#
| flag | effect |
|---|---|
--tools core|forms|all | which tools the agent sees (12, 16 or 21). Fewer tools means less schema in every turn |
--allow-domain example.com (repeatable) | only that domain and subdomains, every request and WebSockets included; example.com:8443 pins a port |
--require-confirm-submit | form_submit fails unless the agent passes confirm=true, so a human can approve |
--upload-dir DIR (repeatable) | file fields may be filled from this directory; without it uploads are refused |
--block-private-networks | with no allowlist, refuse loopback, private, metadata and internal hosts |
--accept-dialogs | answer the page's confirm() and prompt() with OK; they are dismissed by default |
--lean | lower memory; no images, fonts or media |
--profile-dir DIR | persistent Chrome profile (keeps logins); one profile per server |
--headed | visible browser, for watching it work and for wait_for_human |
--learn | save non-sensitive values typed after an accepted submit (off by default) |
The full flag list is on the Configuration and CLI page, and the reasoning is in the Security model.
Tabs share one browser context#
Cookies and logins carry across tabs. The context tool is a small key/value notepad that every tab and every later call can read, for things like "applicant = Ada, order id = 4471". It survives a browser restart. Popups arrive as tabs under the same domain policy.
Other agents: A2A#
If another agent, rather than a coding agent, should hand Ostler a form, use A2A instead of MCP.
Use the Chrome you already have#
Ostler can drive a Chrome you started yourself, so you keep your own window and sessions:
- Start Chrome with a debugging port on loopback and a dedicated profile (Chrome ignores the flag on its default profile; you start this, Ostler never opens the port for you):
- macOS:
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --remote-debugging-address=127.0.0.1 --user-data-dir=$HOME/.ostler/chrome-profile - Linux:
google-chrome --remote-debugging-port=9222 --remote-debugging-address=127.0.0.1 --user-data-dir=$HOME/.ostler/chrome-profile
- macOS:
- Check it:
ostler doctor --cdp-url http://127.0.0.1:9222(opens one blank tab, closes it). - Register it:
ostler install --client claude-code -- --cdp-url http://127.0.0.1:9222.
The one-prompt flow: tell your agent "start Chrome with the command above, then run ostler doctor --cdp-url http://127.0.0.1:9222", then install as in step 3.
Safety: only loopback URLs are accepted (a DevTools port has no authentication: anything that can reach it controls the browser, including every logged-in site), the URL is checked when serve starts, Ostler works in a tab of its own and closes only that tab on exit, and your browser keeps running. While the port is open, any local program can drive that Chrome, so use a dedicated profile and close it when done. --cdp-url conflicts with --profile-dir, is refused in A2A mode, and --allow-domain then relies on request interception without Chrome's DNS pinning.