localmcp
Supports attaching to a running Arc browser over CDP for authenticated browsing and page reading.
Supports attaching to a running Brave browser over CDP for authenticated browsing and page reading.
Enables reading Cloudflare documentation pages, preferring publisher-provided markdown to reduce token usage.
Supports using Firefox as a browser engine, after a one-time Playwright install, for browsing and signed-in sessions.
Enables reading GitHub pages, preferring publisher-provided markdown to reduce token usage.
Supports using Google Chrome as the browser channel or attaching to a running Chrome instance over CDP for authenticated browsing and page reading.
Supports attaching to a running Opera browser over CDP for authenticated browsing and page reading.
Supports WebKit, Safari's engine, as a browser engine; attaching to a running Safari via safaridriver is on the roadmap.
Enables reading Stripe API documentation and signed-in Stripe dashboard pages, using publisher markdown when available and authenticated sessions for private pages.
Enables reading Vercel documentation pages, preferring publisher-provided markdown to reduce token usage.
Supports attaching to a running Vivaldi browser over CDP for authenticated browsing and page reading.
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., "@localmcpread localhost:3000 and focus on the error logs"
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.
localmcp
A local, read-optimized browser for AI agents. Your agent reads any page — including the ones you're signed in to — as focused, token-budgeted markdown. Runs a real Chromium on your machine. No cloud relay, no API key, no account.
claude mcp add localmcp -- npx -y @network101/localmcp # Claude Code
npx @network101/localmcp init # everything else: prints config for your clients · MIT · Node ≥ 20 · Website
Why
Option | Problem for agents |
Built-in web fetch (e.g. Claude Code's WebFetch) | No cookies, no JavaScript, refuses localhost, and large pages come back as a small-model summary rather than the page. |
Cloud scrapers (Firecrawl, Jina, Browserbase) | Your Stripe dashboard, internal wiki, and |
Full automation MCPs (e.g. Playwright MCP) | Great for driving a browser. For reading, one page snapshot is 13k–87k tokens of accessibility tree (measured). |
CLI browser tools | Need a shell. Claude Desktop and other sandboxed clients don't have one. |
localmcp is the reading-first option: the page itself — no summarizer in the middle — focused and under a token budget, read by a browser on your machine. Five MCP tools, or three shell commands. See the benchmark.
Related MCP server: cleanfetch
What's new in 0.2
Real authenticated browsing.
npx @network101/localmcp login <url>opens a visible browser on a private profile. Sign in once; the agent reuses the session. Or attach to your own Chrome over CDP.Focus + budget.
browse({ url, focus: "rate limits", maxTokens: 1500 })ranks sections by relevance and returns only what fits — and tells the agent which sections it left out.Structured extraction with MCP sampling.
extractreturns JSON-LD, meta tags, and tables as row objects. Pass aschemaand your client's own model fills it — no extra API key.Current MCP spec. Tool
annotations,outputSchema+structuredContent, serverinstructions, progress notifications, and diff snapshots as resources.Safety by default. Domain allow/deny policy, read-only mode, dangerous schemes blocked, and every page wrapped in an untrusted-content fence against prompt injection.
Metadata-first reading (0.2.1). If a site publishes markdown for agents (a
text/markdownalternate link, orAccept: text/markdown), localmcp reads that instead of the rendered HTML. Stripe's API reference drops from 428k tokens of HTML to the publisher's own markdown. Every result opens with a page card (type, site, author, published/updated dates, canonical URL, source) read from JSON-LD, OpenGraph,<meta>and front matter, andlinkspoints out a site's/llms.txt.
See CHANGELOG.md for the full list and migration notes.
How a page becomes agent-readable
Ask the publisher. Use a declared
<link rel="alternate" type="text/markdown">on the same origin, or request the page withAccept: text/markdown. Many docs platforms (Stripe, Vercel, Cloudflare, Anthropic, GitHub) serve clean markdown this way. It's used only from the page's own origin and only if it matches the rendered page's title; otherwise the rendered page wins and the result says so.Read the metadata. Use JSON-LD (including
@graph), OpenGraph,<meta>, the canonical link and markdown front matter to build a one-line page card covering what the page is, who wrote it, how fresh it is, and where the text came from.Read the structure. If there's no publisher markdown, render the page, strip chrome (nav, footer, banners, hidden and
aria-hiddennodes), keep semantic landmarks, headings and tables, and convert to GFM.Rank and budget.
focusranks sections;maxTokenscaps the result and lists omitted headings.Fence it. Wrap the result in
<untrusted-page-content>with typedstructuredContent(source,card).
Example card:
> TechArticle · Vercel · updated 2026-09-13 · source: publisher markdown (declared text/markdown alternate)Turn publisher markdown off with "distill": { "publisherMarkdown": false }. Cross-origin alternates are always ignored, so a page can't point the agent at another host.
Tools
Tool | What it does | Annotations |
| Page → clean markdown. | read-only |
| JSON-LD, meta/OpenGraph, tables as rows, headings; optional | read-only |
| De-duplicated absolute links; filter by | read-only |
| Viewport, full page, or one | read-only |
|
| destructive |
Read-only annotations let clients auto-approve reads while still confirming interact.
From a shell
The same tools and policy, with no tool schema in your agent's context:
npx @network101/localmcp read https://docs.stripe.com/api --focus "pagination" --max-tokens 1500
npx @network101/localmcp extract https://example.com/pricing --schema '{"plans":[{"name":"string"}]}' --json
npx @network101/localmcp links https://docs.example.com --same-origin --match /api/--json prints structuredContent; otherwise you get the same fenced markdown the MCP tools return. Exit code 1 means a policy block or a page error.
browse
browse({ url: "https://docs.stripe.com/api", focus: "pagination", maxTokens: 1500 })# Pagination | Stripe API Reference
https://docs.stripe.com/api/pagination · 1,204 tokens · 98% smaller than raw HTML · truncated to budget
> Focus: pagination
<untrusted-page-content source="https://docs.stripe.com/api/pagination">
…the relevant sections, in page order…
</untrusted-page-content>
_Omitted sections — call again with `focus` or a larger `maxTokens` to read them: Errors · Idempotent requests · …_diff: true— first call saves a baseline; later calls return only a unified diff of what changed (the oldwatchtool;watchstill works as an alias).elements: true— appends visible buttons/links/inputs with CSS selectors verified unique in the live DOM, ready forinteract.waitFor: "#app table"— wait for a late-rendering SPA element before reading.
extract
extract({ url: "https://example.com/pricing", schema: { plans: [{ name: "string", price: "string" }] } })structuredContent always contains title, meta, jsonLd[], tables[] ({ headers, rows: [{ header: value }] }), and headings[]. If the client supports sampling, data holds the schema filled by the client's model and method is "sampling"; otherwise the schema is returned as a hint next to the content (method: "dom").
links
links({ url: "https://docs.example.com", sameOrigin: true, match: "/api/" })interact
interact({
url: "http://localhost:3000/signup",
actions: [
{ type: "fill", selector: "input[name='email']", value: "test@example.com" },
{ type: "press", selector: "input[name='email']", value: "Enter" },
{ type: "wait", selector: ".welcome" }
]
})Password values are never echoed back. If an action navigates to a host your policy denies, the result is withheld.
Signed-in pages
Option A: dedicated profile (recommended)
npx @network101/localmcp login https://dashboard.stripe.comA browser window opens on ~/.localmcp/profile. Sign in to whatever your agent should read, then close the window. With the default browser.profile: "auto", localmcp uses that profile from then on. Chromium locks a profile to one process. If two clients run localmcp at once, the second one falls back to an ephemeral session and says so in its output.
Option B: your own Chrome
Start Chrome with --remote-debugging-port=9222, then:
{ "browser": { "cdpEndpoint": "http://localhost:9222" } }localmcp opens its own tabs in your existing session and never closes your browser.
Either way the agent can read anything those sessions can. So while a signed-in session is in use,
interactis off by default (policy.allowInteract: "auto"): the agent reads as you but can't click or type as you until you setallowInteract: true. Pair this withpolicy.allow(below).
Browsers
Browser | How | Status |
Chromium (bundled) | default | ✓ |
Google Chrome, Microsoft Edge |
| ✓ |
Firefox |
| ✓ |
WebKit (Safari's engine) |
| ✓ |
Your running Chrome, Edge, Brave, Arc, Vivaldi, Opera |
| ✓ |
Your running Firefox | WebDriver BiDi attach | Roadmap |
Your running Safari |
| Roadmap |
Tabs in your everyday browser, no flags | extension bridge | Roadmap |
Firefox and WebKit need a one-time npx playwright install firefox webkit. Sign in per engine with npx @network101/localmcp login <url> --browser firefox.
Configuration
npx @network101/localmcp init writes .localmcp.json. Global defaults can live in ~/.config/localmcp/config.json; project config wins.
{
"browser": {
"timeout": 30000,
"headless": true,
"engine": "chromium", // "chromium" | "firefox" | "webkit"
"channel": null, // chromium only: "chrome" | "msedge" | …
"profile": "auto", // "auto" | "persistent" | "ephemeral"
"cdpEndpoint": null // e.g. "http://localhost:9222"
},
"distill": {
"maxTokens": 4000, // default budget for browse/extract/interact
"includeLinks": true,
"includeImages": false,
"publisherMarkdown": true // prefer markdown the site serves for agents
},
"policy": {
"allow": [], // host globs; empty = any. e.g. ["*.stripe.com", "localhost:*"]
"deny": [], // checked first
"allowInteract": "auto", // "auto": off while signed in · true · false (read-only)
"allowFileUrls": false
},
"limits": {
"maxSessionsPerDay": 100, // local circuit breaker against runaway agents
"maxTokensPerDay": 1000000
}
}Host globs: example.com (exact host, any port), *.example.com (subdomains, not the apex), localhost:3000, localhost:*.
Security model
Nothing is relayed. Pages are fetched and distilled by a browser on your machine, then go only to the model your agent already uses. No telemetry, no account.
Policy at the boundary. Every URL is checked before a browser is touched, and again after redirects or actions that change origin. Deny rules also apply to every request a page makes — images, iframes, scripts, fetches — including when attached to your own browser. Only
http(s)is allowed by default;file:,javascript:,chrome:,data:are refused.Prompt-injection fence. Page content comes back inside
<untrusted-page-content>tags, and the server'sinstructionstell the model to treat it as data. Pages that try to close the fence early are neutralised. This reduces injection risk; it doesn't eliminate it. Keepinteractconfirmations on in your client.Circuit breaker. Daily session and token caps (local SQLite at
~/.localmcp/usage.db).npx @network101/localmcp usageshows totals.LOCALMCP_NO_LIMIT=1overrides.
MCP protocol surface
Feature | Support |
| ✓ |
| ✓ |
Server | ✓ |
| ✓ |
| ✓ |
| ✓ |
Transport | stdio |
CLI
localmcp Start the MCP server on stdio
localmcp init Create .localmcp.json and print setup for your MCP clients
localmcp login [url] Sign in once on the persistent profile
localmcp usage Today's and this week's usage
localmcp --versionToken benchmark
npm run bench measures named public pages four ways — rendered HTML, a Playwright MCP browser_snapshot, browse with no budget, and browse with the 4,000-token default — and writes benchmarks/results.md. On 2026-10-01:
Page | Rendered HTML | Playwright MCP snapshot | localmcp (full) | localmcp (default) |
Stripe API reference | 428,457 | 30,724 | 482 | 482 |
GitHub REST: Issues | 330,083 | 87,350 | 20,228 | 4,002 |
Next.js docs | 159,921 | 19,721 | 799 | 799 |
Wikipedia: Model Context Protocol | 109,268 | 20,288 | 6,387 | 3,991 |
Python: json module | 29,700 | 25,381 | 8,624 | 3,996 |
Hacker News front page | 8,539 | 12,207 | 4,023 | 3,945 |
Tokens ≈ characters ÷ 4 in every column. Savings range from 2× (a page that is already mostly text) to hundreds of times (a site serving its own markdown); focus and maxTokens cap any page at the budget you choose. Tool schemas: localmcp 1,352 tokens, Playwright MCP 5,072 — Claude Code, Cursor and Codex load schemas on demand, so this mainly matters for clients that don't.
Development
npm install
npx playwright install chromium
npm test # vitest — unit, browser, and end-to-end MCP protocol tests
npm run buildName
localmcp was previously published as browsermcpai (and headlessdev before that). The old config files, state directory and env override keep working; see the changelog.
It is not affiliated with Browser MCP (browsermcp.io), a Chrome-extension project, nor with the local-mcp and @localmcp/* packages on npm, which give ChatGPT and Claude shell and file access to your machine. localmcp is the opposite kind of tool: a scoped, read-only browser.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Hosted browser for AI agents: screenshots, post-JS DOM, console, WCAG. No install, no API key.
Web scraping for AI agents: scrape, search, crawl, map any website to markdown + JSON. No browser.
Web scraping for agents. Point it at a URL and it returns the page as clean markdown, JavaScript-rendered pages included. Point it at a site and it maps the URLs or crawls the section you need in the background, a few pages at a time so results fit in the conversation. Search the web and read full pages, extract fields with a JSON schema you define (validated, never invented), read a store's catalogue or a blog's posts from the platform's own feed, and check whether a page has changed. Failed requests cost nothing. The free plan includes 1,500 credits a month.
- CrawioOAuthcom.crawio
Web pages as Markdown, text or HTML, plus Google Maps places and reviews, for AI agents.
Related MCP Servers
AlicenseNot gradedqualityBmaintenanceAgent-native headless browser for AI agents. Converts web pages to a Semantic Object Model (SOM) instead of raw HTML — 17x average token reduction across real-world sites (up to 117x on complex pages). Native MCP server with fetch_page, extract_text, extract_links, and full browser automation. No API key required.41 npmApache 2.0- AlicenseAqualityCmaintenanceEnables AI agents to read web pages reliably, returning clean markdown content, hyperlinks, and metadata without navigation or ad noise.39 npmMIT
- AlicenseAqualityDmaintenanceEnables AI agents to fetch any web page as clean markdown or screenshot it, turning URLs into LLM-ready context.27 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to read, screenshot, or convert web pages to PDF using a real headless browser, turning any URL into clean Markdown, a visual image, or a print-ready document.82 npmMIT