farr-browser-mcp
Provides structured facts from Wikipedia article pages, such as infobox rows, via a built-in site skill.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@farr-browser-mcpOpen https://example.com and summarize what's on the page"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
farr-browser
farr-browser lets an AI agent use a web browser the way a careful person does: it opens a page, looks at what can be clicked or typed into, acts, and sees what changed. It keeps the page open between the agent's calls, refuses by default anything that would buy, pay, delete or send, and never acts on a stale view of the page. It also reads pages as clean markdown, downloads files, honours robots.txt and paces its requests to each site.
It runs on your own machine, uses the open-source Playwright to drive Chromium, and works from the command line, from Node.js, or as an MCP server for any MCP client.
Quickstart (5 minutes)
You need Node.js 20 or newer.
npm install -g farr-browser
farr-browser install-browser # downloads the browser this version was built for
farr-browser read https://example.com # the page as markdown
farr-browser open https://example.com # a live session: prints a session id and a lookopen starts a small background daemon the first time; it holds the page open. Its output looks like this:
session: s3f9a1c
Example Domain
https://example.com/
# Example Domain
e1 link "Learn more" → https://iana.org/domains/exampleEach actionable element has a ref (e1). Use the session id and a ref:
farr-browser do s3f9a1c click e1 # prints what changed, then the new look
farr-browser do s3f9a1c back
farr-browser shot s3f9a1c --marks # screenshot with the refs drawn on it
farr-browser close s3f9a1c --trace # close, and list every step takenfarr-browser health checks the installation; farr-browser --help lists every command. If Playwright's Chromium is not installed, an installed Google Chrome or Microsoft Edge is used instead, and health says which.
Related MCP server: agent-browser
Commands
Command | What it does |
| Start a live session; print its id and the first look |
| The page as it is now ( |
|
|
| Screenshot (JPEG) |
| End the session; |
| One-shot read as markdown; |
| Download; |
| List and run site skills |
| Operate the daemon |
| Measured health; the recent operations |
Examples of do:
farr-browser do s3f9a1c type e7 "hello world" --submit # fill a field and press Enter
farr-browser do s3f9a1c select e9 "Newest first"
farr-browser do s3f9a1c wait "Results" # wait for text (or a number of ms)
farr-browser do s3f9a1c goto https://example.org/
farr-browser do s3f9a1c tab 0 # switch tabAdd --json to any command for machine-readable output. Exit codes: 0 done, 1 error, 2 refused.
Use it from an MCP client
The package installs farr-browser-mcp, a stdio MCP server with the tools open, look, do, shot, close, read, get, skills, skill, health and log. Add it to your client's MCP configuration, for example:
{
"mcpServers": {
"farr-browser": { "command": "farr-browser-mcp" }
}
}With Claude Code: claude mcp add farr-browser -- farr-browser-mcp. Without a global install, use "command": "npx", "args": ["-y", "-p", "farr-browser", "farr-browser-mcp"].
The live-session tools talk to the same daemon as the command line, so a session opened by one can be continued by the other.
The safety model
These rules hold for every session, whichever way it is driven.
Stale refs are refused, never clicked. A ref names one element. It keeps working while that element is on the page, and survives later looks. If the element is gone (the page re-rendered or navigated), using its ref is refused, nothing is done, and a fresh look comes back with the refusal. Ref numbers are never reused within a session, so an old ref can never point at something new.
Irreversible controls are refused unless you pass
allow: true(--allowon the command line). A control counts as irreversible when its label says buy, pay, order, bid, delete, send, transfer, cancel an order or subscription, and similar words in English, German, French, Italian and Spanish; or when the form it submits posts to a URL such as/checkout,/payment,/deleteor/transfer. This is a tripwire, not a proof: a purchase button labelled "Continue" on a form with an innocent URL will pass. Passallowonly when a person has asked for exactly that action.Dialogs. An
alert()is acknowledged. Aconfirm()orprompt()is dismissed, which is the answer that does nothing. To accept the next one, arm it first:do <session> dialog accept. Arming covers one dialog only.Everything that happens is reported. New tabs, downloads (saved under the state directory), dialogs and their answers, and navigations stopped by robots.txt appear in the result of the action that caused them. Every action reports what measurably changed (URL, title, amount of text, number of elements, tabs); "nothing changed" is reported as a warning.
robots.txt is honoured for every request: one-shot reads, downloads, each redirect hop, skill requests, and every main-frame navigation in a live session, whether it comes from
goto, a clicked link, a submitted form or the page's own script. If a site's robots.txt cannot be read (server error, network failure), farr-browser refuses rather than assuming permission. A missing robots.txt (HTTP 404) means no restrictions, as the standard says. Requests identify themselves asfarr-browser.Pacing. Requests to one host are spaced by at least
pacing.minIntervalMs(default 1000 ms), or by the site'sCrawl-delay, whichever is longer. Per-site intervals can be set in the config.Refusal pages are not content. When a site answers with an access-denied or "are you a robot" page, or with HTTP 401, 403, 429 or 503, the result is reported as
blocked. A bot challenge is reported as blocked and never worked around.Limits. The daemon holds at most
maxSessionssessions (default 4); a session idle foridleSeconds(default 600) or older thanmaxAgeSeconds(default 4 hours) is closed. It listens only on a local socket in the state directory, readable by your user alone.
farr-browser never logs in, never imports cookies and stores no credentials. Each session starts with an empty browser profile that is discarded when it closes.
Configuration
State and settings live in ~/.farr-browser/ (or the directory in FARR_BROWSER_HOME). Create config.json there to change the defaults:
{
"maxSessions": 4,
"idleSeconds": 600,
"timeoutMs": 30000,
"pacing": { "minIntervalMs": 1000, "sites": { "slow.example.org": 5000 } },
"browser": { "channel": null, "headless": true },
"proxies": []
}The same directory holds log.jsonl (one line per operation, shown by farr-browser log), traces/ (one file per session), downloads/, daemon.log and your own skills/.
Bring your own proxies
farr-browser ships with no proxies and is tied to no provider. List the ones you have, each optionally tagged with a two-letter country code:
{
"proxies": [
{ "server": "http://127.0.0.1:8080" },
{ "server": "socks5://127.0.0.1:1080", "country": "DE" },
{ "server": "socks5://127.0.0.1:1081", "country": "DE" },
{ "server": "http://proxy.internal:3128", "country": "US", "default": true }
]
}--country DE(orcountry: "DE"over MCP) uses a proxy taggedDE, taking turns when there are several. If none is tagged with that country, the request is refused rather than sent another way.A request without a country uses a proxy marked
"default": true, or goes direct if there is none.Supported schemes:
http://,https://,socks5://. Proxies that need a username and password are not supported in this version.robots.txt is fetched through the same proxy as the request it guards.
farr-browser healthchecks that each proxy is reachable.
Write a skill
A skill answers one question about one site with typed rows instead of prose. It is a JSON file; put yours in ~/.farr-browser/skills/. This is the built-in Wikipedia skill:
{
"id": "wikipedia",
"description": "Structured facts from Wikipedia article pages.",
"domains": ["wikipedia.org"],
"intents": {
"infobox": {
"description": "The label and value of every row in an article's infobox.",
"input": {
"title": { "required": true, "spaces": "_", "description": "article title, e.g. Ada Lovelace" },
"lang": { "default": "en", "description": "language edition" }
},
"url": "https://{lang}.wikipedia.org/wiki/{title}",
"format": "html",
"rows": "table.infobox tr",
"fields": {
"label": { "selector": ["th.infobox-label", "th"] },
"value": { "selector": ["td.infobox-data", "td"] }
},
"required": ["label", "value"]
}
}
}farr-browser skill wikipedia infobox title="Ada Lovelace"The parts:
domains: the hosts the skill may fetch (subdomains included). A URL outside them is refused.input: the arguments. Each is URL-encoded into the{name}placeholders ofurl;defaultfills a missing value;spacesreplaces spaces;path: truekeeps slashes;raw: trueinserts the value unencoded.format:htmlorjson.For
html,rowsis a CSS selector for one element per row, and each field has aselector(relative to the row; a list is tried in order; omit it to use the row itself) and optionallyattrto read an attribute instead of the text. The page is parsed with JavaScript switched off and no sub-resources loaded.For
json,rowsis a dotted path to the list (data.items,1for the second element of an array), and each field has an optionalpath(default: the field's name).
typeper field:string(default),number,integerorurl(made absolute).required: rows missing any of these fields are dropped and counted indropped.
Skills fetch through the same path as read: robots.txt, pacing and your proxies apply. farr-browser skills lists every skill with its intents and argument names; farr-browser health reports skill files that fail validation.
Use it from Node.js
const { Sessions, read } = require('farr-browser');
(async () => {
const page = await read('https://example.com');
console.log(page.markdown);
const browser = new Sessions(); // in-process, no daemon
const s = await browser.open({ url: 'https://example.com' });
console.log(s.look);
const r = await browser.act({ session: s.session, action: 'click', ref: 'e1' });
console.log(r.delta, r.look);
await browser.close({ session: s.session });
await browser.shutdown();
})();Development
npm install
npx playwright install chromium
npm testThe tests run entirely offline against fixture pages served by a local HTTP server started inside each test.
License
Apache License 2.0. Copyright 2026 Kiomars Sharifi. See LICENSE and NOTICE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Stealth web browser for agents: search, fetch, click, download and type in persistent MCP sessions.
A real browser for your agent: render any page, or 25 pages of a site, to clean text.
Scrape, crawl and search the web for AI agents via MCP.
Hyperbrowser MCP — wraps the Hyperbrowser AI-agent browsing API
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to operate an isolated local Chromium browser through MCP, with semantic snapshots, ref-based actions, search, research, crawling, and CDP access.Apache 2.0
- AlicenseNot gradedqualityCmaintenanceProvides a headless Chromium browser through MCP, enabling AI agents to browse JavaScript-rendered pages, search the web, capture screenshots, extract tables and data, and run stateful multi-step interactions like clicking, typing, and form submission.1,236,914 npm1MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents and clients to control a real Chromium browser through MCP tool calls, including navigation, clicking, typing, JavaScript evaluation, screenshots, and DOM snapshots. Supports multiple isolated sessions over authenticated HTTP with no disk writes.Apache 2.0
- AlicenseAqualityCmaintenanceEnables browser automation and web data extraction through MCP tools, including Markdown reading, screenshots, structured data extraction, page inspection, and allowlisted site crawling.10386 npmMIT