brightdata-mcp-plus
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., "@brightdata-mcp-plusscrape today's top posts from news.ycombinator.com"
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.
brightdata-mcp-plus is a Model Context Protocol server that gives AI agents (Claude Code, Claude Desktop, Cursor, VS Code, any MCP client) reliable access to live web data: page fetching, search, 1,200+ pre-built scrapers, datasets and remote browsers.
It is a ground-up TypeScript rebuild of the official @brightdata/mcp,
keeping its tool names and environment variables so it works as a drop-in replacement, and adding what it was missing:
free direct fetching and local Chrome rendering, with Bright Data only as the fallback for bot walls, spending
guards, caching, pagination, cancellation, retries, an SSRF guard, a built-in HTTP transport and a real test suite.
Unofficial project, not affiliated with Bright Data. Bright Data features (search, scrapers, unblocking, remote browsers) need your own Bright Data API token and are billed by Bright Data. Page fetching, including JavaScript apps rendered in your own Chrome, works with no account at all.
Contents
Related MCP server: Spider MCP Server
Why it costs less
Bright Data charges per request. Most pages an agent reads (docs, blogs, news, GitHub, package registries, Wikipedia) don't block ordinary requests, so paying a proxy network to fetch them is wasted money. This server tries two free routes first:
Direct fetch from your machine: plain HTTP, fast, works for most of the web.
Local headless Chrome (or Edge) when the page is a JavaScript-only app shell: Spotify, Instagram, YouTube, TikTok, Figma, Duolingo and other single-page apps render for free on your own browser.
Only real bot walls (Cloudflare challenges, DataDome, PerimeterX, CAPTCHAs) go to Bright Data. Repeated fetches come from a cache, also free.
That screenshot is a real run of scripts/live-smoke.mjs against live websites with no API
token. Wikipedia, Hacker News and GitHub were fetched directly. Spotify, Instagram, YouTube and TikTok, which send an
empty shell to plain HTTP clients, were rendered in a local headless Chrome and returned their real content
(follower counts, bios, video and track lists). G2's Cloudflare challenge and Reddit's CAPTCHA were detected; with a
token these go to Bright Data automatically. An attempt to read the cloud-metadata address was refused by the SSRF
guard. Every result tells the agent how it was fetched:
[server] Fetched directly (free).
[server] Rendered in a local headless browser (free): the page needs JavaScript.
[server] Fetched via Bright Data (billed): free routes were not usable (needs_javascript > render:captcha).
[server] Served from cache (originally via free direct fetch; no cost).Quick start
Requires Node.js 22+. Google Chrome or Microsoft Edge is optional: with one installed, JavaScript apps are rendered locally for free; without one they go to Bright Data (or fail in free mode).
git clone https://github.com/wikydtron/brightdata-mcp-plus.git
cd brightdata-mcp-plus
npm install # also builds (prepare script)
npm test # optional: 70 tests, ~10 sOr run it straight from GitHub without cloning:
npx -y github:wikydtron/brightdata-mcp-plus --list-toolsFree mode (no account): start it without API_TOKEN. You get scrape_as_markdown, scrape_batch,
scrape_as_html, extract and session_stats, fetching directly and rendering JavaScript apps in your local Chrome
or Edge (found automatically; set CHROME_PATH otherwise). Add BROWSER_CDP_ENDPOINT to drive your own Chrome with
the interactive browser tools too.
Full mode: set API_TOKEN to unlock search, scrapers, datasets, AI-insights and Bright Data's remote browsers.
Page fetching still tries the free routes (direct, then local Chrome) first, so only bot-walled pages are billed.
Check your token and zones first:
API_TOKEN=your_token node dist/src/index.js --checkConnect your client
claude mcp add brightdata -e API_TOKEN=your_token -- node /absolute/path/to/brightdata-mcp-plus/dist/src/index.jsLeave out -e API_TOKEN=... for free mode.
{
"mcpServers": {
"brightdata": {
"command": "node",
"args": ["/absolute/path/to/brightdata-mcp-plus/dist/src/index.js"],
"env": { "API_TOKEN": "your_token", "BUDGET_MAX_REQUESTS": "500" }
}
}
}{
"mcpServers": {
"brightdata": {
"command": "node",
"args": ["/absolute/path/to/brightdata-mcp-plus/dist/src/index.js"],
"env": { "API_TOKEN": "your_token" }
}
}
}VS Code uses "servers" instead of "mcpServers" as the top-level key.
node dist/src/index.js --transport http --port 3000Clients connect to http://127.0.0.1:3000/mcp with Authorization: Bearer <bright data token>. Each MCP session gets
its own token, cache, budget and browser, so one server can serve several people. ?groups= and ?tools= work like on
Bright Data's hosted server; ?token= is accepted for compatibility but logs a warning because URLs end up in logs.
Binding to a non-loopback address with a shared API_TOKEN requires HTTP_AUTH_SECRET (sent by clients as
x-mcp-auth). Health check: GET /healthz.
docker build -t brightdata-mcp-plus .
docker run -i --rm -e API_TOKEN=your_token brightdata-mcp-plusThe image is a slim Node.js image without a browser, so local rendering is skipped there and JavaScript apps go to Bright Data. Run it with Node directly if you want free rendering.
How page fetching works
| Behaviour | Cost |
| Direct, then local Chrome for JavaScript apps, then Bright Data Web Unlocker for bot walls and failures | Only bot-walled pages are billed |
| Direct and local Chrome only; blocked pages return an error with the reason | Never billed |
| Always Web Unlocker (upstream behaviour) | Every fetch billed |
(no | Free mode: | Free |
Details:
Bot-wall detection looks for Cloudflare challenges, DataDome, Imperva, PerimeterX, AWS WAF, Google's "unusual traffic" page, CAPTCHA widgets and JavaScript-only shells. CAPTCHA keywords only count on short pages, so an article with a reCAPTCHA contact form is still fetched for free. Rendered pages are classified again, so a bot wall that only appears after JavaScript runs is still caught.
Local rendering uses your installed Chrome or Edge through
playwright-core(no browser download). One headless browser is shared by all sessions, each render gets a fresh incognito context, images, media and fonts are skipped, and the browser closes after 2 idle minutes. A render finishes as soon as the app has produced text or its network goes quiet, so an empty shell fails over in about a second instead of waiting out a timeout. The first render after the browser has been closed can take several seconds longer while it starts. It renders pages; it does not try to evade bot detection, so walls still go to Bright Data, which exists for that.Host memory: for 30 minutes, a host that needed rendering skips the direct attempt, and a host that blocked goes straight to Bright Data.
Country routing (
country: "de") always uses Bright Data, since geo-targeting needs a proxy.Direct fetches follow up to 5 redirects, decode gzip/deflate/brotli, honour the page charset, stop at 15 s and 10 MB, and convert HTML to Markdown with absolute links.
Limits: apps that keep streaming data after the first paint (Google Maps, live trading charts) may render only their UI chrome. For structured data from those, use a pre-built scraper (
search_scrapers "google maps") or the interactivescraping_browser_*tools.
Tools (34)
Tool | What it does | Key options |
| Google (ranked JSON), Bing or Yandex (Markdown) |
|
| Up to 10 searches in parallel |
|
| One page as compact Markdown via direct → local Chrome → Bright Data; a note says which |
|
| Up to 10 pages in parallel, each with its |
|
| HTML, paginated (the rendered DOM when the page needed JavaScript) |
|
| Page to JSON using your own model via MCP sampling; fetches like |
|
Tool | What it does |
| Ranked search of the scraper catalog by site, domain, data type or |
| Input fields (with required flags), example input, output fields |
| Validates input before anything is billed, enforces |
| Job status |
| Records with |
| Reload the catalog now |
Tool | What it does |
| Filter search over LinkedIn people and company datasets |
| Ask ChatGPT or Perplexity (for GEO / brand visibility); long jobs return a |
| Bright Data's support assistant, with threaded follow-ups |
| Calls, errors, p50/p95 latency, cache hits, billable units, estimated cost, free direct fetches and local renders, savings, local-rendering status, budget left |
scraping_browser_navigate, _go_back, _go_forward, _snapshot (ARIA refs, optional filtering), _click_ref,
_type_ref, _press_key, _fill_form, _screenshot (JPEG by default), _get_text, _get_html (both paginated),
_scroll (top/bottom/up/down), _scroll_to_ref, _wait_for_ref, _network_requests (filter by type or URL),
_close. Idle browsers close automatically and open sessions are capped.
Prompts: web_scraping_strategy and diagnose_scraping_approach (takes a url).
Configuration
All settings are environment variables (names compatible with @brightdata/mcp). Run --help for CLI flags.
Variable | Default | Purpose |
| — | Bright Data API token. Without it: free mode |
|
|
|
|
| Limits for direct fetches |
| Chrome UA | User-Agent for direct fetches |
|
| Allow direct fetches and renders of localhost/LAN addresses |
|
| Render JavaScript apps in local Chrome/Edge before paying Bright Data ( |
| auto | Browser executable if Chrome/Edge isn't in its standard location |
|
| Per-render limit; close the browser after this idle time |
|
| Direct-fetch results that trigger a local render |
|
| Parallel renders |
|
| Zone names |
|
| Create missing zones at startup |
| all | Limit tools; legacy |
|
| Max billable units per session |
|
| Refuse scraper runs that could return more billed records |
| off | Local limit for all tools, e.g. |
|
| USD per 1K results, for estimates only |
|
| Bright Data API timeout and retries |
|
| Concurrent upstream requests per session |
|
| Response cache ( |
|
| Default page size for content tools |
|
| Prompt-injection gate |
|
| Browser reaping and cap |
| — | Use your own Chromium ( |
| off | Always filter snapshots |
|
| Transport |
| —, | HTTP access secret, idle timeout |
|
|
|
Cost control
Budget:
BUDGET_MAX_REQUESTS=500stops a session before its 501st billable unit. Units are reserved before each call, so parallel calls can't overshoot together. Cached pages stay available after the budget is spent.Scraper guard:
run_scraperrefusesdiscover_by_*runs whose worst case (inputs × limit_per_input) exceedsMAX_RECORDS_PER_RUN, and checks required input fields before triggering, so typos are never billed.No double billing: job triggers are retried only when Bright Data rejected them (429), never after a timeout that may have started a job.
Visibility:
session_statsreturns
{
"fetch_strategy": "auto",
"local_rendering": "on",
"billable": { "unlocker_requests": 3, "scraper_records": 10, "dataset_records": 0, "browser_navigations": 0 },
"estimated_cost_usd": 0.0195,
"free": { "direct_fetches": 42, "local_renders": 9, "fallbacks": 3, "estimated_savings_usd": 0.0765 },
"budget": { "max": 500, "used": 13, "remaining": 487 },
"tools": { "scrape_as_markdown": { "calls": 45, "errors": 0, "cache_hits": 6, "p50_ms": 410, "p95_ms": 1890 } }
}Security model
Threat | Defence |
Prompt injection in web content | Every web result is wrapped between |
Pages telling the agent to change its MCP config | Content gate: matching content is withheld unless the user approves it through MCP elicitation |
SSRF (agent tricked into reading | Direct fetches resolve DNS and refuse private, loopback, link-local and metadata ranges on every redirect hop; the local renderer only opens URLs whose redirect chain passed that check, blocks every in-page request to those ranges, and discards a page that ends up on one |
Credential leaks | API token, zone passwords and URL credentials are redacted from logs and errors; the token is never put in a URL |
Ambiguous browser refs | A ref that appears more than once in the snapshot (e.g. echoed by page text) is refused |
Exposed HTTP server | Loopback by default, DNS-rebinding protection, |
Architecture
src/
index.ts CLI: flags, --check, --list-tools, stdio startup, graceful shutdown
config.ts Validated config (env + flags)
server.ts createSession(): one isolated McpServer + services; the tool pipeline
http/client.ts The only path to the Bright Data API: auth, timeouts, retries, concurrency, typed errors
http/server.ts Streamable HTTP transport with per-session isolation
services/ pages (direct → render → Bright Data), direct (SSRF-safe fetch + classifier),
render (local headless Chrome), unlocker, serp, scrapers, datasets, assistant,
browser, zones
tools/ Tool definitions (zod schemas, annotations), grouped by area
security/ Untrusted-content wrapping, prompt-injection content gate
usage.ts Stats, budget reservations, rate limiting, savings
util/ Cache, semaphore, pagination, Markdown minifier, redactionCompared with @brightdata/mcp
Area |
| brightdata-mcp-plus |
Page fetching | Every fetch billed | Direct, then local headless Chrome for JavaScript apps (both free), Bright Data only for bot walls; free mode with no account |
Language | ~2.8k lines of untyped JS | Strict TypeScript, layered |
Timeouts | None by default; two tools ignore | Every call (90 s default) |
Retries | Off by default, no backoff | Jittered backoff, |
Cancellation | Ignored; polling can run 10 min after the client gave up | Aborts requests, polling and queued work |
Batch size | Docs say 10, code allows 5 | 10 |
Caching | None | TTL + LRU, single-flight |
Large pages | Returned whole | Paginated with |
Cost guards | None | Budget, per-run record cap, pre-billing input validation |
Free-tier message | Missing for scraper and browser tools | Every tool |
| Browser tools skip it | Every tool |
| Samples from the first session, not the caller | Calling session, optional JSON Schema |
HTTP | Hosted only, token in URL | Built in, header auth, per-session isolation |
SSRF protection | n/a | Private-range guard on every redirect hop and on every request inside the local browser |
Docker | Image copies 3 of 15 modules | Multi-stage, non-root, healthcheck |
Tests | Unit and stub tests | 70: unit, fake Bright Data API, real MCP clients over in-memory/stdio/HTTP, real headless Chrome (CDP and local rendering) |
Development
npm run build # tsc
npm test # build + 70 tests (browser and render tests use local Chrome/Edge if found)
npm run typecheck
node scripts/live-smoke.mjs # real sites, free mode, no cost
node scripts/live-smoke.mjs --json assets/src/live-run.json # refresh demo data
node scripts/render-assets.mjs # re-render README images (needs Chrome/Edge)Test suites: unit (config, cache, semaphore, errors, security, SERP, pagination, scoring, budget),
client (retries, Retry-After, timeouts, cancellation, headers), e2e (all tool families through a real MCP client),
direct (direct fetching, bot-wall detection, fallback, SSRF, free mode), render (local Chrome: client-rendered
pages, XHR, walls that appear after JavaScript, host memory, in-browser SSRF guard), http (multi-tenant HTTP),
stdio (the built CLI as a subprocess) and browser (a real headless Chrome over CDP).
FAQ
Is it free? Fetching pages directly and rendering them in your own Chrome is free. Bright Data's own services (search, scrapers, unblocking protected sites, remote browsers) run on their infrastructure and are billed to your Bright Data account; their free tier is 5,000 requests a month. This server just makes sure you only use them when needed.
Why did a page cost a request? The result note says why, e.g. cloudflare_challenge or
needs_javascript > render:captcha (a JavaScript app that showed a CAPTCHA even to a real browser). Use
FETCH_STRATEGY=direct to never pay, at the cost of failing on protected sites.
Do I need Chrome? No. Without Chrome or Edge the render step is skipped: the first page that needs it falls
through to Bright Data with the reason render:unavailable, and from then on session_stats shows
local_rendering: "unavailable (no Chrome/Edge found)". Set CHROME_PATH if your browser is in a non-standard
place, or LOCAL_RENDER=off to skip the attempt entirely.
Is direct fetching and local rendering allowed? Both are ordinary requests from your machine, the same as opening the page in your browser. You are responsible for respecting each site's terms and robots rules.
Is this official? No. It's an independent MIT-licensed project derived from brightdata/brightdata-mcp (MIT, see LICENSE.upstream).
License
Available Tools
5 toolsextractExtract Structured DataARead-only
Fetch a page and turn it into JSON using your own model via MCP sampling (no extra Bright Data cost beyond the page fetch). Pass extraction_prompt and optionally a JSON Schema in schema to shape the output.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | ||
| fresh | No | Bypass the response cache and fetch again (costs a request) | |
| schema | No | Optional JSON Schema the output must follow | |
| country | No | 2-letter country code to route the request through (e.g. "us", "de") | |
| extraction_prompt | No | What to extract |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds genuine context beyond the annotations: extraction runs through MCP sampling on the caller's model, and there is no extra Bright Data cost beyond the page fetch. It also implicitly signals caching via the fresh parameter's cost note. It doesn't disclose failure behavior when the model returns schema-invalid JSON, which is the main remaining gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no waste; the mechanism and cost note come first and the parameter call-to-action second. Every clause carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description must convey the return shape and does (JSON, optionally constrained by a provided schema), and the cost model is covered. Missing only edge-case behavior such as what happens on extraction or schema-validation failure.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 80%, so most parameters are already documented in-schema (fresh, country, schema, extraction_prompt). The description reinforces that extraction_prompt is the core input and schema is optional shaping, but adds no syntax or format detail beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Fetch a page') and transformation ('turn it into JSON') plus the non-obvious mechanism (MCP sampling with the caller's own model). This distinguishes it functionally from scrape_as_markdown/scrape_as_html, though it never names those siblings, so an agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use it (when you want structured JSON shaped by a prompt/schema) and notes the cost profile, but gives no explicit when-to-use/when-not guidance relative to scrape_as_markdown or scrape_as_html. The choice must be inferred from the output format implied by each tool name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scrape_as_htmlScrape as HTMLARead-onlyIdempotent
Fetch one page and return its raw HTML, paginated with offset/max_chars. Prefer scrape_as_markdown unless you need markup, attributes or embedded JSON. Pages are fetched directly for free when the site allows it, rendered in a local headless browser (also free) when they need JavaScript, and fetched through Bright Data Web Unlocker (billed) only when the site blocks; a note after the result says which.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | ||
| fresh | No | Bypass the response cache and fetch again (costs a request) | |
| offset | No | Character offset to start from; use next_offset from a truncated result | |
| country | No | 2-letter country code to route the request through (e.g. "us", "de") | |
| max_chars | No | Maximum characters to return (default: server MAX_OUTPUT_CHARS) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/openWorld/idempotent/non-destructive, but the description adds substantive behavior beyond them: a three-tier fetch strategy (free direct, free headless render, billed Bright Data unlocker) and the fact that the result includes a note stating which path was taken. This billing/cost disclosure is exactly the kind of context annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, each front-loaded with the most actionable information: what it returns first, the alternative second, the cost model third. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description still covers return format (raw HTML, character offsets), the cost/billing implications, and the fallback ladder. Nothing an agent needs to select or call this tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 80%, so the schema already documents most params. The description adds workflow meaning by framing offset/max_chars as a pagination pair and implying the truncated-result flow, though it doesn't explain the interaction with next_offset beyond what the schema says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Fetch one page and return its raw HTML') plus its pagination model, and explicitly contrasts with the scrape_as_markdown sibling so an agent can choose without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names the preferred alternative and the exact condition to deviate: 'Prefer scrape_as_markdown unless you need markup, attributes or embedded JSON.' That is a clear when-to-use and when-not-to-use rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scrape_as_markdownScrape as MarkdownARead-onlyIdempotent
Fetch one web page and return it as compact Markdown. Pages are fetched directly for free when the site allows it, rendered in a local headless browser (also free) when they need JavaScript, and fetched through Bright Data Web Unlocker (billed) only when the site blocks; a note after the result says which. Long pages are paginated: when truncated, call again with the returned offset. Use format=raw for the unprocessed Markdown.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | ||
| fresh | No | Bypass the response cache and fetch again (costs a request) | |
| format | No | markdown: compact Markdown keeping headings, lists, tables, links (default); text: plain text with links; raw: as fetched | markdown |
| offset | No | Character offset to start from; use next_offset from a truncated result | |
| country | No | 2-letter country code to route the request through (e.g. "us", "de") | |
| max_chars | No | Maximum characters to return (default: server MAX_OUTPUT_CHARS) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/openWorld/idempotent annotations, the description discloses the three-tier fetch strategy (direct free, headless browser free, Bright Data billed only on block) and that a note after the result identifies which path was used. The truncation/pagination behavior is also spelled out, which is exactly the kind of cost and output behavior annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the core action, then cost behavior, then pagination and format tips. Every sentence carries distinct information with no repetitive restatement of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries return-value burden and does explain the post-result note and pagination offsets. Minor gap: it says 'returned offset' while the schema field is next_offset, and it doesn't describe the shape of the Markdown payload beyond 'compact'.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 83%, so the schema already documents nearly every parameter, including format, offset, fresh, and max_chars. The description adds only the format=raw recommendation and the offset-retry loop, which is marginal value over structured data. The 3 baseline applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource — 'Fetch one web page and return it as compact Markdown' — and the 'one web page' scope implicitly separates it from scrape_batch. It doesn't explicitly name siblings like scrape_as_html or extract, so the differentiation is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear operational guidance: use format=raw for unprocessed Markdown, and call again with the returned offset when a page is truncated. It also explains the fetch cost ladder, which tells an agent what to expect. It stops short of saying when to prefer scrape_as_html or extract over this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scrape_batchScrape BatchARead-onlyIdempotent
Fetch up to 10 pages in parallel and return [{url, ok, source, content | error}] as JSON. Each page is capped (max_chars_per_url); fetch a single page with scrape_as_markdown to read past the cap. Pages are fetched directly for free when the site allows it, rendered in a local headless browser (also free) when they need JavaScript, and fetched through Bright Data Web Unlocker (billed) only when the site blocks; source says which.
| Name | Required | Description | Default |
|---|---|---|---|
| urls | Yes | ||
| fresh | No | Bypass the response cache and fetch again (costs a request) | |
| format | No | markdown: compact Markdown keeping headings, lists, tables, links (default); text: plain text with links; raw: as fetched | markdown |
| country | No | 2-letter country code to route the request through (e.g. "us", "de") | |
| max_chars_per_url | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say readOnly/idempotent/openWorld; the description adds the critical non-obvious behavior: a three-tier fetch strategy (free direct, free local headless browser, billed Bright Data Web Unlocker only when blocked) and the fact that `source` reports which tier was used. That cost/permission disclosure is exactly the context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, no waste: return shape first, then the cap plus escape hatch, then the fetch/cost model. Each sentence carries distinct information the agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by specifying the exact response shape and the meaning of `ok`, `source`, `content`/`error`. Combined with the disclosed billing model for the Bright Data tier, an agent has everything needed to call it correctly and predict cost.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 60%; the description supplies meaning for the undocumented max_chars_per_url (each page is capped) and explains the `source` field in the response, which the schema does not cover. It does not add anything about `country`, `fresh`, or `format` beyond what the schema already documents.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (fetch), resource (up to 10 pages in parallel) and the exact return shape [{url, ok, source, content | error}], plus names the sibling scrape_as_markdown as the single-page alternative. An agent can distinguish it from scrape_as_markdown, scrape_as_html and extract without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent to scrape_as_markdown when it needs to read past the per-page cap, which is a real selection criterion. It does not spell out when to prefer batch vs. the other siblings (scrape_as_html, extract), so it stops short of full when/when-not coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
session_statsSession StatsARead-only
Usage this session: calls, errors, latency (p50/p95) and cache hits per tool, billable units, estimated cost, free direct fetches and savings, remaining budget, zone status and open browser sessions.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| free | Yes | |
| cache | Yes | |
| tools | Yes | |
| zones | Yes | |
| budget | Yes | |
| billable | Yes | |
| uptime_s | Yes | |
| fetch_strategy | Yes | |
| upstream_calls | Yes | |
| local_rendering | Yes | |
| estimated_cost_usd | Yes | |
| open_browser_sessions | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, openWorldHint=false, and destructiveHint=false, so the safety profile is clear. The description adds the list of reported metrics, which is useful but overlaps with the output schema and does not disclose other behavioral traits (e.g., refresh cadence or whether the stats are real-time). With annotations covering safety, a 3 is appropriate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence that enumerates the metrics efficiently. It is dense but not wasteful, though a brief introductory verb (e.g., 'Returns') would make it slightly more scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a zero-parameter read-only tool with an output schema and clear annotations, the description is sufficiently complete: it tells the agent what categories of data are available. It could be improved by specifying when to call it, but that is covered under usage guidelines.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero parameters, so the baseline is 4. The description adds no parameter semantics because none exist, but the schema is empty and needs no further explanation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly indicates this tool returns session usage statistics, enumerating the specific metrics (calls, errors, latency, cost, budget, zone status, browser sessions). The resource and scope are identifiable, and the sibling tools (scraping/extraction) are unrelated, so no differentiation is needed.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent would infer this is for checking session health and cost. There is no explicit when-to-use guidance, no mention of alternatives, and no exclusions. It is adequate but minimal.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v1.2.0- First observed
extract - First observed
scrape_as_html - First observed
scrape_as_markdown - First observed
scrape_batch - First observed
session_stats
TDQS
Scored across 5 tools
Each tool has a clearly distinct purpose: single-page Markdown, single-page HTML, parallel batch fetching, structured extraction, and session statistics. The descriptions explicitly distinguish when to use HTML versus Markdown and when to use batch versus single-page calls. There is little risk of misselection.
Three scraping tools use a consistent scrape_* pattern, but extract and session_stats deviate from that prefix. All names are readable snake_case and descriptive, so the inconsistency is minor rather than confusing.
Five tools is well-scoped for a web scraping server. Each tool earns its place by covering a distinct access mode or operational need.
The surface covers single-page Markdown, raw HTML, batch fetching, structured extraction, and usage monitoring, which is strong lifecycle coverage for scraping. Minor gaps could include explicit cache management or site-status checks, but core workflows are covered.
Maintenance
Related MCP Connectors
Live web access for agents: scrape, SERP search, crawl/map, 100+ collectors, datasets, proxies.
Reliable web access for AI agents: smart HTTP, rotating proxies, and full-browser rendering.
Web data for agents: YouTube transcripts, screenshots, Google News, WHOIS, jobs, tech stack, more.
Search, scrape, and crawl the web for AI agents. Batch scraping and answers with citations.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables LLMs and AI agents to access real-time web data, search websites, and navigate the web without getting blocked. Includes 5,000 free monthly requests and supports web scraping, browser automation, and bypassing geo-restrictions.6011,741 npm1MIT
- AlicenseAqualityCmaintenanceEnables AI agents to crawl, scrape, search, and automate browsers with anti-bot bypass, providing fast web access via 22 tools.2211 npm3MIT
- AlicenseBqualityDmaintenanceEnables AI agents to browse and extract data from any public website via Bright Data's cloud infrastructure, handling proxy rotation, CAPTCHA solving, and JavaScript rendering.57MIT
- AlicenseAqualityAmaintenanceProvides AI agents live web access through scraping, multi-engine search, site mapping, crawling, SEO audits, and 31 data collectors via natural language tool calls.957 npmMIT