FourA MCP
OfficialFourA MCP gives AI agents reliable web access by fetching public URLs with automatic method selection, rotating proxies, or full browser rendering.
foura_auto— smart fetch: give a URL and it returns content, automatically choosing HTTP, proxy, or browser and handling common bot challenges.foura_single— send one HTTP request with customizable method, headers, body, timeouts, redirects, browser profile (Chrome/Edge/Safari/Firefox/Tor), OS, and version.foura_proxy— route requests through rotating proxies with retries, country allowlists (exitCountries), premium exits, and reuse of successful proxy IDs.foura_browser— run a full browser session for JavaScript-heavy pages, SPAs, lazy-loaded content, and anti-bot challenges; returns rendered HTML, cookies, and user agent.Response validation — validate by status codes, body substrings, or headers; pass only when the real content appears, not a challenge page.
Typed structured outputs — every tool returns predictable JSON with error codes, credits, request IDs, timing, and session/reuse values.
Six built-in prompts — smart fetch, product page scraping, article extraction, price monitoring, endpoint health checks, and bulk URL fetching.
Large-response handling — optional offload of bodies ≥50 KB to MCP resource links to save tokens.
Composable sessions — reuse proxy IDs, cookies, and user agents across
foura_single,foura_proxy, andfoura_browser.Runs locally via stdio or hosted via Streamable HTTP, with a single
FOURA_API_KEYauthenticating all tools.
Allows bypassing Akamai Bot Manager challenges and extracting content from Akamai-protected websites.
Allows bypassing Cloudflare anti-bot challenges and extracting content from Cloudflare-protected websites.
Allows bypassing Vercel's security checkpoint and extracting content from Vercel-deployed sites.
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., "@FourA MCPfetch https://example.com and bypass anti-bot challenges"
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.
Start with foura_auto: one URL in, typed content out. It chooses the appropriate fetch method and handles common blocks for you. Use foura_single, foura_proxy, or foura_browser when you want explicit control over the request path.
Start simple | Reach difficult pages | Build predictable agent flows |
One default tool for most URLs | HTTP, proxy rotation, and full-browser rendering | Typed outputs, stable error codes, and six ready-made prompts |
The included workflows cover product extraction, article cleanup, price monitoring, endpoint checks, and bulk URL fetching.
Use it from Claude Desktop, Claude Code, Cursor, Windsurf, VS Code, or any MCP client. Run the npm package locally or connect to the hosted Streamable HTTP endpoint with the same FourA API key.
Get an API key | Read the MCP docs | See the package on npm
One-click install:
Both buttons pre-fill the config with a YOUR_FOURA_API_KEY placeholder - replace it with your key. Or by hand: claude mcp add foura -- npx -y @fouradata/mcp (set FOURA_API_KEY in env first). Full per-client setup below.
Quick Start - local stdio (recommended for Claude Desktop)
Create or reveal an API key at foura.ai/dashboard/#api-keys (format pk_live_...). Then drop this into your MCP client's config:
{
"mcpServers": {
"foura": {
"command": "npx",
"args": ["-y", "@fouradata/mcp"],
"env": {
"FOURA_API_KEY": "pk_live_..."
}
}
}
}Claude Desktop gotcha: fully quit Claude Desktop (
Cmd+Qon macOS) before editing the config file. If the app is still running, it will overwrite your edits with its in-memory config on exit.
The npx command downloads the package on first launch and runs it as a subprocess of your MCP client. No global install needed. The same JSON works across MCP clients; only the config-file location changes:
Client | Where the config lives |
Claude Desktop (macOS) |
|
Claude Desktop (Windows) |
|
Claude Code |
|
Cursor |
|
Windsurf |
|
VS Code (MCP extension) |
|
Restart the client and foura_auto, foura_single, foura_proxy, foura_browser show up in your tool list, plus six prompts under /prompts.
Related MCP server: Bright Data MCP
Quick Start - hosted (Streamable HTTP)
If your client supports the Streamable HTTP transport, point it at the hosted endpoint instead of running a local subprocess:
{
"mcpServers": {
"foura": {
"url": "https://mcp.foura.ai/mcp",
"headers": {
"Authorization": "Bearer pk_live_..."
}
}
}
}For Claude Desktop, use the stdio config above. You can also bridge the hosted endpoint through mcp-remote:
{
"mcpServers": {
"foura": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.foura.ai/mcp", "--header", "Authorization: Bearer pk_live_..."]
}
}
}The Tools
foura_auto is the default - give it a URL and it returns the content, choosing the fetch method for you. The other three tools give you direct control over HTTP, proxy rotation, and browser rendering.
All four are marked readOnlyHint: true and openWorldHint: true per the MCP specification. Clients can use those annotations when deciding how to present or approve tool calls.
Every response carries human-readable text (content) plus a typed structuredContent JSON object validated against the tool's outputSchema. Your agent gets a predictable response contract instead of parsing prose.
foura_auto - smart fetch (the default)
Give it a URL and get the content back. Use this first when you don't want to choose between HTTP, proxy rotation, and browser rendering. It handles common bot challenges and keeps the client surface small, with no proxy-attempt tuning required.
{
"url": "https://example.com",
// optional: a substring the real page must contain, so auto can tell a
// real page from a challenge page on protected targets
"validate": { "data": { "accept": ["Example Domain"] } }
}The client surface is intentionally minimal: url (required), plus optional method, headers, data, validate, returnSession (default true), forceProxy (default true), timeout_ms (5000-180000, default 120000), ignoreProxies.
structuredContent shape: {status, headers, data, meta, session}. meta is always present - {rung, solved, attempts, credits} - so your agent can see how the request completed and how many credits it used. session ({proxy, cookies, userAgent}) is returned by default for follow-up requests (pass session.proxy into the proxy field). Send returnSession: false to omit it. There is no total_time field on auto.
foura_single - fast HTTP
One HTTP request, response back. Use it for static pages, JSON APIs, and server-rendered HTML. unblocker defaults to true, so the request already carries a full browser header set; set it to false for a plain HTTP request.
{
"method": "GET",
"url": "https://example.com"
}Supports custom headers, a body, per-stage timeouts, redirect controls, JSON auto-parse, a binary-buffer mode, and built-in response validation (validate.status.accept, validate.data.fail, and so on). If foura_single comes back blocked - status 403/429, a captcha page, challenge response headers, or a known challenge title - try a different browser profile (below), then escalate to foura_proxy. Start with maxTries: 5; protected targets may need 25-30. If the page also needs JavaScript to render, pass foura_proxy's returned proxy ID to foura_browser.proxy.
structuredContent shape: {status, headers, data, total_time, ...}. When the target ran a bot check, the response also carries defense; defense.solved: false means the body may be a challenge page rather than the content you asked for.
Choosing which browser you present
By default a request presents the latest Google Chrome. Some targets accept one browser and refuse another, so foura_single and foura_proxy let you pick:
{
"method": "GET",
"url": "https://example.com",
"browser": "Firefox",
"os": "Windows"
}browser-Chrome,Edge,Safari,Firefox, orTor.os-Windows,macOS,Android, oriOS. A family name accepts any of its versions; the exact labels in the catalogue narrow further.version- any version the catalogue lists for that browser. The newest match wins when several fit.profile- an exact id from the catalogue, when you already have one.
The full catalogue is public at api.foura.ai/api/profiles, no key required, and its default field names the profile a request gets when you ask for nothing. Selection needs unblocker on, which is the default. A combination that does not exist returns an error listing what is available, so a request is never quietly sent as a browser you did not choose.
foura_proxy - rotating proxies with retry
Same target shape as foura_single, but routed through rotating proxies with automatic retry on failure. Use it when a direct request is blocked or when the target requires a specific exit country.
{
"maxTries": 5,
"exitCountries": ["CZ", "GB"],
"request": {
"method": "GET",
"url": "https://example.com/pricing",
"browser": "Chrome",
"os": "Windows"
}
}structuredContent adds proxy (the encoded ID of the proxy that succeeded) and total (outer timing including selection and retries). When the rotation had to move to another browser family to get an answer, profile names the family it settled on; replay with it or the next call repeats the version that failed. exitCountries is optional: values are trimmed, uppercased, and deduplicated; proxies with unknown exits are excluded; the request never falls back to an unrequested country. Selection uses the latest available country metadata, normally updated within ten minutes, and a scoped success returns that value as exitCountry. If no eligible proxy matches, the result uses code: "no_eligible_proxy".
The inner request takes the same browser-profile fields as foura_single: browser, os, version, or an exact profile.
exitClass - for a target the standard pool cannot reach. Set exitClass: "premium" and the request may escalate to a premium exit instead of only rotating within the standard pool. It is an allowance, not an instruction: the standard pool still races for the answer and usually wins, and a request it answers before any premium exit is tried costs no premium traffic. Once a premium exit has been tried, the traffic it carried counts toward your premium allowance even if that attempt failed; an attempt still running when another exit answered is stopped and not counted. The response reports exitClass back, premium or standard, so you can see per request which one served you. standard is also the answer once the premium traffic in your plan is spent, and it is a normal result, not an error. exitClass: "standard" forbids escalation outright. On a plan without premium exits the call is refused with code: "plan_limit_premium".
attemptReport - why a rotation ran out of tries. Every failed foura_proxy result carries it beside the error. summary is one sentence; the counts underneath separate causes with opposite fixes: noResponse (the exit never answered), defense (a bot check was recognised, named in vendors), contentRejected (HTTP 200, no bot check, rejected only by your own validate.data), statusRejected, and other. profilesTried lists the browsers the task sent, in first-use order, with default meaning the request went out exactly as written. A high contentRejected means the pages arrived and your own rule threw them away: fetch one with foura_single and no validate, look at it, and rewrite the rule.
For difficult WAF challenges, use maxTries: 25-30. For a country allowlist, set exitCountries instead of increasing attempts. If the target needs JavaScript rendering, pass the returned proxy ID to foura_browser.proxy.
foura_browser - full browser session
A real browser session. JavaScript runs, the DOM finishes rendering, cookies come back with the response. Use it when the page is a single-page app, when content lazy-loads after first paint, or when there's an anti-bot challenge that needs a real browser to clear.
{
"url": "https://example.com/spa",
"timeout_ms": 15000,
"checkText": "data-table"
}Use this when an HTTP response isn't enough. checkText validates the rendered HTML once navigation completes; it doesn't wait or poll. If the substring is missing, the call fails with an error envelope. This catches pages that return 200 without the content you need. unblocker defaults to true and handles supported anti-bot or captcha challenges along the way. Set it to false to return the page exactly as it loads, challenge included.
structuredContent shape is intentionally different from single/proxy: {status, headers (object, not array), body (not data), cookies (full browser cookie shape), userAgent}.
Built-in Prompts
Six workflow templates surfaced under /prompts in your MCP client. They orchestrate one or more tools without you spelling out the steps.
Prompt | Arguments | What it does |
|
| Pick the method, handle bot protection, and return or extract content |
|
| Extract title, price, image, stock, and SKU as JSON in a browser session |
|
| Fetch an article, retry through a proxy if needed, and remove page chrome |
|
| Fetch the current price and compare it with a target |
|
| Validate reachability, status, content, and timing |
|
| Fetch URLs in parallel, retry blocked ones, and return metadata |
Each prompt arrives as a templated user message your LLM executes with the right tools. The full prompt text enters the context only when you invoke it.
Full recipe text + manual fallback prompts: foura.ai/docs/mcp/recipes. For the full error code list, see foura.ai/docs/mcp/errors.
Authentication
Use FOURA_API_KEY in stdio mode or an Authorization: Bearer pk_live_... header with the hosted endpoint. One key authenticates all four tools.
Keys are managed in the dashboard, where you can create, reveal, rotate, or deactivate them. See foura.ai/docs/getting-started/authentication for the full key-management walkthrough.
Error envelope - typed contract for agent retries
Every error (isError: true) carries a structuredContent envelope with at minimum these three fields:
{
"service": "auto" | "single" | "proxy" | "browser",
"code": "ssrf_blocked" | "auth_failed" | "rate_limited" | ...,
"error": "Human-readable message"
}Where the upstream returned a status, you also get status (HTTP code) and on rate-limit / capacity errors the FourA API envelope adds retryAfter, current.{concurrency, rpm}, limits.{maxConcurrency, maxRpm}.
| When | Retry safe? |
| Target resolves to a private or reserved address | No - change the URL |
| Upstream returned malformed body | Maybe - investigate |
| Input shape rejected by FourA | No - fix arguments |
| Key missing, invalid, or deactivated | No - fix the key |
| Authenticated but not allowed | No |
| Target / endpoint doesn't exist | No |
| RPM cap hit | Yes - wait |
| Concurrency cap hit | Yes - wait |
| Maintenance window | Yes - wait |
| Generic 503 | Yes - short backoff |
| Upstream 5xx | Yes - exponential backoff |
| Other 4xx | Usually no |
| No proxy matches the requested | No - change the country scope |
| Your own FourA plan refused the call, not the target | Only |
A plan_limit_ code names which of your plan's limits refused the call: credits, bandwidth, rate, concurrency, browser_daily, premium, or feature. It is not the target blocking you, so retrying the same work through another tool spends the rest of the allowance for nothing. Wait out retryAfter where there is one, or change the plan.
LLM agents can read code directly for retry logic without parsing prose. Spec reference: foura.ai/docs/api/errors.
What every result carries
Beside the tool's own fields, each result reports what the call cost and how to trace it:
credits- credits this call spent, on failures as well, because the work was done either way;request_id- FourA's id for the call. Quote it in a support request;exitClass-premiumwhen a premium exit served the call. Onfoura_singleandfoura_browserthat happens whenproxyreplays an exitfoura_proxyfound.
Combining the tools - reuse the same exit
The lower-level tools compose. foura_proxy returns the base36 ID of the exit it used. Pass that ID into foura_single.proxy or foura_browser.proxy to reuse the same exit for the next request.
// 1. Find a working exit. Difficult protected targets may need maxTries:25-30.
const r = await foura_proxy({
maxTries: 30,
request: { method: "GET", url: "https://probe.example.com" }
});
// Returns { status: 200, proxy: "4DZ3VE", ... }
// 2. Reuse it for follow-up HTTP
await foura_single({ method: "GET", url: "https://target/api", proxy: r.proxy });
// 3. Or render JavaScript through the same exit.
await foura_browser({ url: "https://target/spa", proxy: r.proxy });For a protected JavaScript page, find a working route with foura_proxy before calling foura_browser. Starting in the browser can return the challenge page before the real content loads.
To choose a different proxy on the next foura_proxy call, pass the previous ID as ignoreProxies: ["4DZ3VE"]. The proxy field on foura_single and foura_browser also accepts raw URLs (http://host:port, socks5://...) if you have your own list.
Large responses - offload_large (default: inline)
By default (since v0.2.0), full response bodies are returned inline in structuredContent regardless of size. This works in every MCP client.
If your client supports MCP resources/read (and you want to save tokens on big pages), pass offload_large: true per tool call. Responses of 50 KB or more are returned as a resource_link, and your client fetches the body only when it needs it. The resource remains available for one hour.
{
"method": "GET",
"url": "https://en.wikipedia.org/wiki/Web_scraping",
"offload_large": true // opt in for token savings
}Support for MCP resource links varies by client. Leave offload_large at its default false if your client can't read resource_link blocks.
Only the API key that created an offloaded resource can read it back.
Limits and responsible use
Private targets are refused. Requests to private or reserved addresses are blocked at the MCP layer. Only public-internet hosts are forwarded.
Rate limits are enforced by the FourA API per service. Concurrency + RPM. Details at foura.ai/docs/api/rate-limits.
Use FourA only for public content you are authorized to access and in accordance with the target site's terms and applicable law.
Run it yourself
Run the stdio server directly from npm with npx -y @fouradata/mcp, or build the included Dockerfile for the Streamable HTTP transport.
Configurable environment:
Variable | Default | Purpose |
|
| HTTP listen port |
|
| Upstream FourA REST base URL |
|
| Where responses of 50 KB or more are cached on disk |
See DEVELOPMENT.md for the local build and test workflow.
License
MIT. See LICENSE.
Links
FourA (web scraping API): https://foura.ai
MCP server page: https://foura.ai/mcp
Source (GitHub): https://github.com/fouradata/mcp
npm package: https://www.npmjs.com/package/@fouradata/mcp
API documentation: https://foura.ai/docs
MCP server reference: https://foura.ai/docs/mcp/server
MCP error codes: https://foura.ai/docs/mcp/errors
MCP recipes: https://foura.ai/docs/mcp/recipes
REST API errors: https://foura.ai/docs/api/errors
MCP specification: https://modelcontextprotocol.io
Get a key: https://foura.ai/dashboard/#api-keys
Available Tools
4 toolsfoura_autoFourA - auto (smart fetch, picks the method for you)ARead-onlyInspect
Give it a public URL and get the content back. Use it when only the content matters and not how it is fetched: it escalates from a direct request to a rotating proxy to a full browser only as far as the target forces, and returns the session that worked so the next call can replay it. On protected targets, or whenever HTTP 200 may still be a challenge or an incomplete page, pass validate.data.accept with text unique to the real content; auto makes bounded attempts and returns either validated content or a failure, and cannot guarantee a match. It owns its own retry settings, so there is no maxTries here, and timeout_ms is the budget for every attempt together rather than for one. What it cannot do is the reason to reach for another tool: a strict exit country, a pinned exit and a premium exit live on foura_proxy (auto can only avoid exits, through ignoreProxies); choosing which browser is presented to the target lives on foura_single and foura_proxy; a scripted browser session lives on foura_browser. A request that names any of those belongs there rather than here. One FourA API key authenticates every call, the result reports the credits it spent, which is the sum of the attempts it made, and a refusal by your own plan arrives as a plan_limit_ code with retryAfter rather than as a block by the target.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Public target URL. Private or reserved targets return `ssrf_blocked`. Use {ts} in the URL to insert the current Unix timestamp. Example: https://example.com/page. | |
| data | No | Request body for non-GET methods. Strings sent as-is; objects auto-serialized to JSON. | |
| method | No | HTTP method for the target request (default GET). | |
| headers | No | Custom HTTP headers as [name, value] tuples. Example: [["Accept", "application/json"], ["Authorization", "Bearer ..."]] | |
| validate | No | Post-fetch response validation. When the response fails these checks foura_auto returns an error envelope. | |
| forceProxy | No | Require proxy routing for every target request. Default true. Send false to allow direct HTTP when suitable. | |
| timeout_ms | No | Total time budget in ms for the whole operation. Every attempt must fit inside it. Default 120000, max 180000. | |
| ignoreProxies | No | Exits to avoid - base36 proxy IDs (like "4DZ3VE") or proxy URLs. Use this to rotate away from an exit that was just blocked. | |
| offload_large | No | If true, response bodies of 50 KB or more are returned as a resource_link instead of inlined. Default false. Read the returned offloaded_resource_uri with resources/read. | |
| returnSession | No | Return reusable {proxy, cookies, userAgent} values for follow-up calls. Default true. Send false for a leaner response when you only need the content. | |
| followRedirects | No | Follow up to N redirects for HTTP and proxy requests. Default 5; 0 means don't follow. Browser navigation handles redirects itself. |
Output Schema
| Name | Required | Description |
|---|---|---|
| code | No | Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. Other codes: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive). A plan_limit_* code is the caller's own FourA plan refusing (credits, bandwidth, rate, concurrency, browser_daily, premium, feature), not the target: wait out retryAfter or change the plan, never retry the same work through another tool. |
| data | No | Decoded response body of the delivered page. String by default; object when the body parsed as JSON. Omitted when offloaded. |
| meta | No | Completion details: rung, solved, attempts, and credits. Always present. |
| error | No | Human-readable error message when the request could not deliver content within the budget. |
| limits | No | Per-service limits at error time |
| status | No | HTTP status code from the request that delivered the content. `0` means no HTTP response was received; check `error`. |
| credits | No | Credits this call spent. Reported on failures too: the work was done either way. |
| current | No | Caller's current usage at error time |
| headers | No | Response headers from the successful request, as an array of objects. Each entry has `result.{version, code, reason}` plus header-name keys. The last entry is the final response. |
| service | No | |
| session | No | Reusable {proxy, cookies, userAgent} values for follow-up calls. For plain HTTP, call foura_single with session.proxy as proxy, session.userAgent as a User-Agent header, and session.cookies serialized as a Cookie header. For JavaScript, pass the three values to foura_browser fields. Present by default; send returnSession:false to omit. |
| attempts | No | Total attempts when the request failed (also present inside `meta`). |
| request_id | No | FourA's id for this call, for a support request. |
| retryAfter | No | Seconds to wait before retrying a 429 or 503 response |
| size_bytes | No | Total offloaded body size in bytes |
| offloaded_resource_uri | No | foura-mcp://payload/<uuid>. Pass this URI to resources/read to retrieve the offloaded body. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations (readOnlyHint=true, destructiveHint=false, openWorldHint=true) align with a read-only fetch, and the description layers substantial behavioral context on top: the escalation model (direct → rotating proxy → full browser), that it owns its retry settings ('there is no maxTries here'), that timeout_ms is a total budget across all attempts, credit reporting as sum of attempts, the plan_limit_ error code with retryAfter, and session replay via returnSession. This far exceeds what annotations disclose.
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 tool makes appropriate use of a longer description given its complexity (11 params, nested objects, 3 routing siblings). The core purpose is front-loaded, and every sentence earns its place — escalation, validation, timeout semantics, and sibling routing all carry unique information. The main deduction is that the whole thing runs as one dense, unbroken paragraph, which reduces scannability for an agent.
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?
For a tool this complex — escalation behavior, bounded retry, validation, credit accounting, error-code semantics, and three siblings — the description is remarkably complete. An output schema exists so return values need no explanation. Together with the 100%-coverage schema, nothing an agent needs to invoke this 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 100% with unusually rich per-parameter descriptions (validate accept/fail semantics, timeout as whole-operation budget, header tuple format), so the baseline of 3 applies. The description adds marginal guidance beyond the schema, notably on when to set validate.data.accept ('with text unique to the real content') and reaffirming timeout_ms spans all attempts, but it does not systematically explain parameters — the schema carries that burden. No clear gap to push higher.
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 opening sentence 'Give it a public URL and get the content back' states a specific verb and resource. The title adds 'smart fetch, picks the method for you,' and the second sentence sharpens the scope: 'Use it when only the content matters and not how it is fetched.' The 'What it cannot do' paragraph explicitly names each sibling (foura_proxy, foura_single, foura_browser) and the feature that lives there, so an agent can separate this tool from all three without opening their schemas.
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 gives an explicit when-to-use condition ('when only the content matters and not how it is fetched') and an explicit when-not ('a strict exit country, a pinned exit and a premium exit live on foura_proxy... choosing which browser... lives on foura_single and foura_proxy... a scripted browser session lives on foura_browser'). It closes with 'A request that names any of those belongs there rather than here,' leaving no routing ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
foura_browserFourA - full browser navigationARead-onlyInspect
Load a public URL in a full browser session. JavaScript runs, the DOM renders, and cookies come back with the response. Use it for single-page apps, lazy-loaded content, or supported browser challenges. You can set your own headers, cookies and userAgent, and checkStatus or checkText turn a navigation that rendered the wrong page into a failure instead of returning it as content. For a protected page, call foura_proxy first and pass its returned proxy ID here to reuse that same exit, instead of starting a new selection here; with no proxy the session leaves from one fixed address. Set unblocker:false when you want the page exactly as it loads, challenge included. It is the most expensive of the four tools and the slowest, so prefer foura_single or foura_proxy whenever the content is already in the HTML. One FourA API key authenticates every call, the result reports the credits it spent, and a refusal by your own plan arrives as a plan_limit_ code, including plan_limit_browser_daily when the daily browser allowance is spent.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Public URL to load in a full browser session. Private or reserved targets return `ssrf_blocked`. Example: https://shop.example.com/product/123. | |
| proxy | No | Optional proxy. Three forms: (1) URL `http://user:pass@host:port` or `socks5://host:port`; (2) base36 ID from foura_proxy (e.g. `4DZ3VE`) to reuse the same exit; (3) omit to use the default route. | |
| cookies | No | Cookies to set before navigation: [{ name, value, domain? }] | |
| headers | No | Custom HTTP headers as a key-value object rather than [name, value] tuples. Example: {"Referer": "https://google.com/"} | |
| checkText | No | Validate the rendered HTML once navigation completes. This is a substring check, not a waiter, and it doesn't poll. A missing substring returns an error envelope. Example: "add to cart" for a product page. | |
| unblocker | No | Handle supported anti-bot or captcha challenges during navigation. Default true. Set false to return the page exactly as it loads, including any challenge page. | |
| userAgent | No | Override the browser's User-Agent string | |
| timeout_ms | No | Page load timeout in ms (default 30000, max 120000) | |
| checkStatus | No | Expected HTTP status code. A different status returns an error envelope carrying the actual value. Example: 200 for a product page. | |
| offload_large | No | If true, response bodies of 50 KB or more are returned as a resource_link instead of inlined. Default false. Read the returned offloaded_resource_uri with resources/read. |
Output Schema
| Name | Required | Description |
|---|---|---|
| body | No | Fully-rendered page content. String HTML when content-type is HTML; object when the page returned JSON and it was auto-parsed. Field is named `body`, not `data`. Omitted when offloaded. |
| code | No | Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. Other codes: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive). A plan_limit_* code is the caller's own FourA plan refusing (credits, bandwidth, rate, concurrency, browser_daily, premium, feature), not the target: wait out retryAfter or change the plan, never retry the same work through another tool. |
| error | No | Human-readable error message |
| limits | No | |
| status | No | HTTP status code from the target page. `0` indicates the navigation failed before any HTTP response (DNS / connection refused / timeout) - check the `error` field for the underlying reason. |
| cookies | No | Full cookie objects collected after navigation, including name, value, domain, path, expiry, and same-site settings. |
| credits | No | Credits this call spent. Reported on failures too: the work was done either way. |
| current | No | |
| headers | No | Response headers as a flat key-value object. Values are typically strings but may be arrays for repeated headers. |
| service | No | |
| exitClass | No | `premium` when a premium exit served this call, which happens when `proxy` replays one from foura_proxy. |
| userAgent | No | The User-Agent the browser session presented |
| request_id | No | FourA's id for this call, for a support request. |
| retryAfter | No | |
| size_bytes | No | Total offloaded body size in bytes |
| offloaded_resource_uri | No | foura-mcp://payload/<uuid>. Pass this URI to resources/read to retrieve the offloaded body. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/openWorld/destructive annotations, the description discloses important runtime behavior: JavaScript executes, cookies are returned, the default exit uses one fixed address, checkStatus/checkText convert wrong-page renders into failures, and the tool reports credit costs and plan_limit_ errors. It also states unblocker:false returns challenge pages exactly as loaded. This is substantial behavioral context the annotations do not provide.
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 single paragraph is dense but every sentence earns its place, covering use cases, alternatives, proxy integration, cost, auth, and failure semantics. It could be better structured with bullets or separated concerns, but it is not padded or redundant.
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?
For a complex tool with 10 parameters and an output schema, the description covers selection guidance, behavioral caveats, cost, authentication, error codes, and alternative routing. An agent has enough context to invoke it correctly or decide not to, and the output schema handles return-value specifics.
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 already 100%, so the baseline is 3. The description adds genuine value by explaining validation semantics for checkStatus/checkText, the meaning of unblocker:false, and proxy reuse semantics. It does not exhaustively detail every parameter, but it contextualizes the most behaviorally important ones.
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: 'Load a public URL in a full browser session' and immediately gives concrete use cases: single-page apps, lazy-loaded content, and browser challenges. It also distinguishes itself from siblings by naming foura_single and foura_proxy as cheaper alternatives, so an agent can tell the tools apart.
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 explicitly says to prefer foura_single or foura_proxy when content is already in the HTML, and instructs calling foura_proxy first for protected pages and passing its ID here. This gives clear when-to-use and when-not-to-use routing guidance, with named alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
foura_proxyFourA - HTTP request via rotating proxiesARead-onlyInspect
Route an HTTP request through rotating proxies, retrying on another exit until one delivers. Use it when foura_single is blocked, and whenever the exit itself matters: this is the only tool that takes a strict exit-country allowlist (exitCountries, which never falls back to another country), presents a named browser family per attempt, excludes exits you already know are dead (ignoreProxies), and may escalate to a premium exit (exitClass, an allowance rather than an instruction). maxTries bounds how many exits are tried and timeout_ms bounds the whole rotation, so a short timeout can end it before maxTries is reached; protected targets often need 25 to 30. validate decides what counts as delivered, and an attempt it rejects is retried on the next exit. The response returns the id of the exit that succeeded: pass that returned id to foura_single.proxy or foura_browser.proxy to send the next request from the same exit. A failed rotation returns attemptReport, which separates exits that never answered from exits a bot check refused from pages your own rule threw away. Use foura_browser when the page needs JavaScript. Rotation costs several times a single request. One FourA API key authenticates every call, the result reports the credits it spent, and a refusal by your own plan arrives as a plan_limit_ code with retryAfter rather than as a block by the target.
| Name | Required | Description | Default |
|---|---|---|---|
| request | Yes | The inner HTTP request to send through each proxy attempt. Validation rules here determine when a proxy is treated as failed and retried. | |
| maxTries | No | Maximum rotation attempts before giving up (default 5, max 90). Difficult protected targets may need 25-30. Use exitCountries for country scope. | |
| exitClass | No | Allow escalation to a premium exit for a target the standard pool cannot deliver. An allowance, not an instruction: the pool still races and usually wins, and the response reports which class served. `standard` forbids escalation. Without premium exits in the plan the call is refused with code plan_limit_premium. | |
| timeout_ms | No | Overall timeout across all rotation attempts in ms (default 45000, max 120000). Must be positive. | |
| exitCountries | No | Optional target-visible proxy countries as two-letter provider codes, for example ["CZ", "GB"]. Use codes supplied by the user or target requirements. When geography matters, do not guess codes or substitute unscoped rotation. Values are trimmed, uppercased, and deduplicated. Unknown exits are excluded and the request never falls back to another country. | |
| ignoreProxies | No | Encoded proxy IDs (base36 strings like "4DZ3VE") or proxy URLs to exclude from rotation. | |
| offload_large | No | If true, response bodies of 50 KB or more are returned as a resource_link instead of inlined. Default false. Read the returned offloaded_resource_uri with resources/read. |
Output Schema
| Name | Required | Description |
|---|---|---|
| code | No | Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. no_eligible_proxy means the strict exitCountries scope had no match. Keep that scope and retry later; do not propose or perform an unscoped fallback. A plan_limit_* code is the caller's own FourA plan refusing (credits, bandwidth, rate, concurrency, browser_daily, premium, feature), not the target: wait out retryAfter or change the plan, never retry the same work through another tool. |
| data | No | Decoded response body. Omitted when offloaded. |
| error | No | Human-readable error message |
| proxy | No | Base36 ID of the exit that succeeded (e.g. `4DZ3VE`). Pass it to foura_single.proxy or foura_browser.proxy to reuse that exit, or to foura_proxy.ignoreProxies to skip it on future rotations. |
| total | No | Outer total time in seconds (proxy selection + retries + the successful inner attempt). Float. |
| limits | No | |
| status | No | HTTP status code from the target (from the succeeding proxy attempt). `0` indicates every attempt failed before any HTTP response (DNS / connection refused / timeout) - check the `error` field for the underlying reason. |
| credits | No | Credits this call spent. Reported on failures too: the work was done either way. |
| current | No | |
| defense | No | Present when the target ran a bot check. When solved is false the body may be a challenge page: retry with a different browser, os, or version, or move to foura_browser. |
| details | No | Structured no_eligible_proxy context containing the normalized requested country scope. Preserve this scope and retry later. Do not propose or perform an unscoped fallback; change it only after the user explicitly changes the requirement. |
| headers | No | Response headers per redirect hop, as an array of objects. Each entry has `result.{version, code, reason}` plus arbitrary header-name keys whose values are strings (or arrays of strings for multi-value headers like Set-Cookie / Link). |
| profile | No | The browser family rotation moved to after the target refused the one this request sent. Absent means it went out as written; when present, replay with it or repeat the version that failed. |
| request | No | Echoed PrRequest from upstream PrResponseError |
| service | No | |
| exitClass | No | Which class delivered, when the request named exitClass. `standard` means the standard pool answered first, which is also the answer once the premium allowance is spent. Neither is an error. |
| request_id | No | FourA's id for this call, for a support request. |
| retryAfter | No | |
| size_bytes | No | Total offloaded body size in bytes |
| total_time | No | Per-attempt wall-clock duration of the succeeding inner request |
| exitCountry | No | Latest available two-letter target-visible exit-country code used for selection. Present on successful requests that use exitCountries. |
| attemptReport | No | Why a failed rotation ran out of tries. Read `summary` first. Counts over `total` attempts: noResponse (the exit never answered), defense (a bot check was recognised, named in `vendors`), contentRejected (HTTP 200, no bot check, rejected only by your validate.data), statusRejected (rejected by your validate.status), other. `profilesTried` lists the browsers sent, `default` meaning the request went out as written. High contentRejected means the pages arrived and your own rule threw them away: fetch once with foura_single and no validate, then rewrite it. |
| offloaded_resource_uri | No | foura-mcp://payload/<uuid>. Pass this URI to resources/read to retrieve the offloaded body. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Description discloses extensive behaviors beyond annotations: never falls back on exitCountries, presents named browser family, excludes dead exits, escalates to premium as allowance, timeout bounds whole rotation, validate defines delivered, response returns exit id for reuse, and reports credits and plan refusals. No contradiction with readOnlyHint/openWorldHint.
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?
Long but every sentence earns its place, with core purpose and key constraints front-loaded. No filler; complex rotation behavior is explained efficiently without redundancy.
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?
For a tool with 7 params, nested objects, and output schema, the description covers all critical operational aspects: rotation logic, validation, retries, failure reporting, credits, plan limits, and how to chain with sibling tools. Nothing an agent needs to call it 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?
Though schema covers all parameters (100%), the description adds crucial interplay semantics: how timeout_ms can end rotation before maxTries, exitClass is an allowance not instruction, exitCountries never falls back, ignoreProxies excludes known-dead exits, and validate triggers retry. It explains the returned id's reuse, enriching schema meaning.
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?
Clearly states the tool routes HTTP requests through rotating proxies with retry on different exits, and explicitly contrasts it with foura_single (when blocked) and foura_browser (when JS needed). Verb+resource+scope are precise, making it easily distinguishable from siblings.
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 when to use this tool (foura_single blocked, exit matters), when not to (foura_browser for JS), and notes rotation costs. Gives concrete conditions like strict exit-country allowlist and premium escalation, leaving no ambiguity about selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
foura_singleFourA - single HTTP requestARead-onlyInspect
Send one HTTP request and return the response. Use it for static pages, JSON APIs, and server-rendered HTML, with your own headers, body and cookies. Set browser, os, or version when a target refuses the default Chrome. Pass a proxy id returned by foura_proxy to leave from that same exit. validate decides what counts as success, so a response it rejects comes back as a failure instead of as content; the timeouts nest, with timeout_ms bounding the whole request and the connect, accept and server_response ones bounding stages inside it. Switch to foura_proxy when the response is blocked or the exit country matters, and to foura_browser when the page needs JavaScript. One FourA API key authenticates every call, the result reports the credits it spent, and a refusal by your own plan arrives as a plan_limit_ code with retryAfter rather than as a block by the target.
| Name | Required | Description | Default |
|---|---|---|---|
| os | No | Operating system to present: Windows, macOS, Android, or iOS. A family name accepts any of its versions. | |
| url | Yes | Public target URL. Private or reserved targets return `ssrf_blocked`. Use {ts} in the URL to insert the current Unix timestamp. Example: https://api.example.com/v1/users. | |
| data | No | Request body. Strings sent as-is; objects auto-serialized to JSON. Example: {"query": "hello"} for POST APIs. | |
| proxy | No | Optional proxy. Two forms: (1) URL `http://host:port` or `socks5://host:port`; (2) base36 ID from foura_proxy (e.g. `4DZ3VE`) to reuse the same exit. For rotation, use foura_proxy. | |
| method | Yes | HTTP method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, or any WebDAV verb like PROPFIND/MKCOL) | |
| browser | No | Browser to present: Chrome, Edge, Safari, Firefox, or Tor. Omit every profile field and the request presents the latest Google Chrome. | |
| headers | No | Custom HTTP headers as [name, value] tuples. Example: [["Accept", "application/json"], ["Referer", "https://google.com/"]] | |
| profile | No | Exact profile id from the public catalogue at https://api.foura.ai/api/profiles. Use browser/os/version when you do not have an id. | |
| version | No | Browser version to present, as listed in the catalogue. The newest match wins when several fit. An impossible combination returns an error listing what is available; no other browser is substituted. | |
| validate | No | Post-fetch response validation. When the response fails these checks the tool returns an error envelope. | |
| unblocker | No | Send a full browser header set, including User-Agent and Sec-Ch-Ua. Default true. Set false for a plain HTTP request; profile selection needs it on and errors when it is off. | |
| timeout_ms | No | Overall request timeout in ms (max 120000, default 15000) | |
| tryJsonData | No | If true, attempt JSON.parse on the response body. On success, `data` is the parsed value (typically object or array). On parse failure, `data` silently stays as the original string - no error, no warning. Set false (or omit) when you need to detect parse failures explicitly. | |
| returnBuffer | No | Return raw bytes as a serialized Buffer JSON shape (`{type:"Buffer", data:[byte, ...]}`, bytes 0-255) instead of decoded string. Use for binary responses (images, protobuf). Reconstruct: `Buffer.from(data.data)` in Node, `new Uint8Array(data.data)` elsewhere. | |
| offload_large | No | If true, response bodies of 50 KB or more are returned as a resource_link instead of inlined. Default false. Read the returned offloaded_resource_uri with resources/read. | |
| followRedirects | No | Max number of redirects to follow (0-20). Omit to disable redirect following. | |
| accept_timeout_ms | No | Timeout in ms to receive the first response byte after the request is sent (0-120000). Omit for the default. | |
| connect_timeout_ms | No | Timeout in ms for establishing the TCP/TLS connection (0-120000). Omit to use the default. | |
| dns_cache_timeout_sec | No | How long (seconds) to cache the target's resolved DNS (0-240). Omit for the default. | |
| server_response_timeout_ms | No | Timeout in ms for the server to send the complete response (0-120000). Omit for the default. |
Output Schema
| Name | Required | Description |
|---|---|---|
| code | No | Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. Other codes: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive). A plan_limit_* code is the caller's own FourA plan refusing (credits, bandwidth, rate, concurrency, browser_daily, premium, feature), not the target: wait out retryAfter or change the plan, never retry the same work through another tool. |
| data | No | Decoded response body. String by default; object when tryJsonData=true and the body parsed as JSON; serialized Buffer JSON shape (`{type:"Buffer", data:[byte, ...]}`, bytes 0-255) when returnBuffer=true - reconstruct with `Buffer.from(data.data)` in Node, `new Uint8Array(data.data)` elsewhere. Omitted when offloaded. |
| error | No | Human-readable error message |
| limits | No | Per-service limits at error time |
| status | No | HTTP status code from the target. `0` indicates the request failed before any HTTP response (DNS failure, connection refused, timeout) - check the `error` field for the underlying reason. |
| credits | No | Credits this call spent. Reported on failures too: the work was done either way. |
| current | No | Caller's current usage at error time |
| defense | No | Present when the target ran a bot check. When solved is false the body may be a challenge page: retry with a different browser, os, or version, or move to foura_proxy or foura_browser. |
| headers | No | Response headers per redirect hop, as an array of objects. Each entry has `result.{version, code, reason}` plus arbitrary header-name keys whose values are strings (or arrays of strings for multi-value headers like Set-Cookie / Link). Last array entry is the final response. |
| service | No | |
| exitClass | No | `premium` when a premium exit served this call, which happens when `proxy` replays one from foura_proxy. |
| request_id | No | FourA's id for this call, for a support request. |
| retryAfter | No | Seconds to wait before retrying (429/503) |
| size_bytes | No | Total offloaded body size in bytes |
| total_time | No | Wall-clock request duration in seconds. Number when present; string in some variants; null when the request never started. |
| offloaded_resource_uri | No | foura-mcp://payload/<uuid>. Pass this URI to resources/read to retrieve the offloaded body. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavioral context beyond the annotations: it explains timeout nesting ('timeout_ms bounding the whole request and the connect, accept and server_response ones bounding stages inside it'), validation semantics ('validate decides what counts as success'), proxy reuse ('Pass a proxy id returned by foura_proxy to leave from that same exit'), credit reporting, and plan-limit error handling. There is no contradiction with the readOnlyHint/openWorldHint/destructiveHint annotations.
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 dense paragraph that front-loads the core purpose, then flows into use cases, behavioral details, and error handling. Every sentence contributes unique information—there is no filler or repetition. The structure is logical and efficient for the tool's complexity.
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?
For a tool with 20 parameters, nested objects, and an output schema, the description covers all essential behavioral aspects an agent needs: when to use it, timeout nesting, validation, proxy reuse, and plan-limit error handling. Parameter details are in the schema, and the output schema handles return structure, so nothing critical is missing. The description is complete for correct invocation.
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?
The schema covers 100% of parameters with descriptions, so the baseline is 3. The description adds value by explaining cross-parameter behaviors (timeout nesting, validate's effect on success/failure, proxy id reuse) that the schema's individual field descriptions do not convey. It does not go into detail on every parameter, but the schema handles that. This is above baseline.
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 states a specific verb and resource: 'Send one HTTP request and return the response.' It then lists concrete use cases (static pages, JSON APIs, server-rendered HTML) and distinguishes itself from siblings by naming when to use foura_proxy and foura_browser. This gives the agent an unambiguous understanding of the tool's role.
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 gives explicit when-to-use and when-not-to-use guidance: 'Use it for static pages, JSON APIs, and server-rendered HTML' and 'Switch to foura_proxy when the response is blocked or the exit country matters, and to foura_browser when the page needs JavaScript.' It also explains when to set browser/os/version (when a target refuses the default Chrome). This leaves no ambiguity about tool selection.
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.
4 tool updates
v0.7.2- Changed
foura_auto6 fields changed- added
Input schema / properties / headers / items / additionalItemsAdded value: +false - added
Input schema / properties / headers / items / maxItemsAdded value: +2 - added
Input schema / properties / headers / items / minItemsAdded value: +2 - changed
Output schema / properties / code / descriptionPrevious value: -"Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. Other codes: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive)."New value: +"Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. Other codes: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive). A plan_limit_* code is the caller's own FourA plan refusing (credits, bandwidth, rate, concurrency, browser_daily, premium, feature), not the target: wait out retryAfter or change the plan, never retry the same work through another tool." - added
Output schema / properties / creditsAdded value: +{ + "description": "Credits this call spent. Reported on failures too: the work was done either way.", + "type": "number" +} - added
Output schema / properties / request_idAdded value: +{ + "description": "FourA's id for this call, for a support request.", + "type": "string" +}
- Changed
foura_browser4 fields changed- changed
Output schema / properties / code / descriptionPrevious value: -"Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. Other codes: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive)."New value: +"Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. Other codes: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive). A plan_limit_* code is the caller's own FourA plan refusing (credits, bandwidth, rate, concurrency, browser_daily, premium, feature), not the target: wait out retryAfter or change the plan, never retry the same work through another tool." - added
Output schema / properties / creditsAdded value: +{ + "description": "Credits this call spent. Reported on failures too: the work was done either way.", + "type": "number" +} - added
Output schema / properties / exitClassAdded value: +{ + "description": "`premium` when a premium exit served this call, which happens when `proxy` replays one from foura_proxy.", + "enum": [ + "standard", + "premium" + ], + "type": "string" +} - added
Output schema / properties / request_idAdded value: +{ + "description": "FourA's id for this call, for a support request.", + "type": "string" +}
- Changed
foura_proxy12 fields changed- added
Input schema / properties / exitClassAdded value: +{ + "description": "Allow escalation to a premium exit for a target the standard pool cannot deliver. An allowance, not an instruction: the pool still races and usually wins, and the response reports which class served. `standard` forbids escalation. Without premium exits in the plan the call is refused with code plan_limit_premium.", + "enum": [ + "standard", + "premium" + ], + "type": "string" +} - added
Input schema / properties / request / properties / headers / items / additionalItemsAdded value: +false - added
Input schema / properties / request / properties / headers / items / maxItemsAdded value: +2 - added
Input schema / properties / request / properties / headers / items / minItemsAdded value: +2 - added
Output schema / properties / attemptReportAdded value: +{ + "additionalProperties": false, + "description": "Why a failed rotation ran out of tries. Read `summary` first. Counts over `total` attempts: noResponse (the exit never answered), defense (a bot check was recognised, named in `vendors`), contentRejected (HTTP 200, no bot check, rejected only by your validate.data), statusRejected (rejected by your validate.status), other. `profilesTried` lists the browsers sent, `default` meaning the request went out as written. High contentRejected means the pages arrived and your own rule threw them away: fetch once with foura_single and no validate, then rewrite it.", + "properties": { + "contentRejected": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "defense": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "noResponse": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "other": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "profilesTried": { + "items": { + "type": "string" + }, + "type": "array" + }, + "statusRejected": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "summary": { + "type": "string" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "vendors": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" +} - changed
Output schema / properties / code / descriptionPrevious value: -"Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. no_eligible_proxy means the strict exitCountries scope had no match. Keep that scope and retry later; do not propose or perform an unscoped fallback."New value: +"Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. no_eligible_proxy means the strict exitCountries scope had no match. Keep that scope and retry later; do not propose or perform an unscoped fallback. A plan_limit_* code is the caller's own FourA plan refusing (credits, bandwidth, rate, concurrency, browser_daily, premium, feature), not the target: wait out retryAfter or change the plan, never retry the same work through another tool." - added
Output schema / properties / creditsAdded value: +{ + "description": "Credits this call spent. Reported on failures too: the work was done either way.", + "type": "number" +} - added
Output schema / properties / exitClassAdded value: +{ + "description": "Which class delivered, when the request named exitClass. `standard` means the standard pool answered first, which is also the answer once the premium allowance is spent. Neither is an error.", + "enum": [ + "standard", + "premium" + ], + "type": "string" +} - added
Output schema / properties / profileAdded value: +{ + "description": "The browser family rotation moved to after the target refused the one this request sent. Absent means it went out as written; when present, replay with it or repeat the version that failed.", + "type": "string" +} - added
Output schema / properties / request_idAdded value: +{ + "description": "FourA's id for this call, for a support request.", + "type": "string" +} - removed
Output schema / properties / total_time / anyOfRemoved value: -[ - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "null" - } -] - added
Output schema / properties / total_time / typeAdded value: +[ + "number", + "string", + "null" +]
- Changed
foura_single9 fields changed- added
Input schema / properties / headers / items / additionalItemsAdded value: +false - added
Input schema / properties / headers / items / maxItemsAdded value: +2 - added
Input schema / properties / headers / items / minItemsAdded value: +2 - changed
Output schema / properties / code / descriptionPrevious value: -"Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. Other codes: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive)."New value: +"Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. Other codes: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive). A plan_limit_* code is the caller's own FourA plan refusing (credits, bandwidth, rate, concurrency, browser_daily, premium, feature), not the target: wait out retryAfter or change the plan, never retry the same work through another tool." - added
Output schema / properties / creditsAdded value: +{ + "description": "Credits this call spent. Reported on failures too: the work was done either way.", + "type": "number" +} - added
Output schema / properties / exitClassAdded value: +{ + "description": "`premium` when a premium exit served this call, which happens when `proxy` replays one from foura_proxy.", + "enum": [ + "standard", + "premium" + ], + "type": "string" +} - added
Output schema / properties / request_idAdded value: +{ + "description": "FourA's id for this call, for a support request.", + "type": "string" +} - removed
Output schema / properties / total_time / anyOfRemoved value: -[ - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "null" - } -] - added
Output schema / properties / total_time / typeAdded value: +[ + "number", + "string", + "null" +]
2 tool updates
v0.6.0- Changed
foura_proxy6 fields changed- added
Input schema / properties / request / properties / browserAdded value: +{ + "description": "Browser to present: Chrome, Edge, Safari, Firefox, or Tor. Omit every profile field and the request presents the latest Google Chrome.", + "type": "string" +} - added
Input schema / properties / request / properties / osAdded value: +{ + "description": "Operating system to present: Windows, macOS, Android, or iOS. A family name accepts any of its versions.", + "type": "string" +} - added
Input schema / properties / request / properties / profileAdded value: +{ + "description": "Exact profile id from the public catalogue at https://api.foura.ai/api/profiles. Use browser/os/version when you do not have an id.", + "type": "string" +} - changed
Input schema / properties / request / properties / unblocker / descriptionPrevious value: -"Add common browser headers such as User-Agent, Sec-Ch-Ua, and Accept-Encoding. Default false. Enable it for targets that reject basic HTTP requests."New value: +"Send a full browser header set, including User-Agent and Sec-Ch-Ua. Default true. Set false for a plain HTTP request; profile selection needs it on and errors when it is off." - added
Input schema / properties / request / properties / versionAdded value: +{ + "description": "Browser version to present, as listed in the catalogue. The newest match wins when several fit. An impossible combination returns an error listing what is available; no other browser is substituted.", + "type": "string" +} - added
Output schema / properties / defenseAdded value: +{ + "additionalProperties": {}, + "description": "Present when the target ran a bot check. When solved is false the body may be a challenge page: retry with a different browser, os, or version, or move to foura_browser.", + "properties": { + "solved": { + "description": "True when the check was met and `data` is the real page.", + "type": "boolean" + } + }, + "type": "object" +}
- Changed
foura_single6 fields changed- added
Input schema / properties / browserAdded value: +{ + "description": "Browser to present: Chrome, Edge, Safari, Firefox, or Tor. Omit every profile field and the request presents the latest Google Chrome.", + "type": "string" +} - added
Input schema / properties / osAdded value: +{ + "description": "Operating system to present: Windows, macOS, Android, or iOS. A family name accepts any of its versions.", + "type": "string" +} - added
Input schema / properties / profileAdded value: +{ + "description": "Exact profile id from the public catalogue at https://api.foura.ai/api/profiles. Use browser/os/version when you do not have an id.", + "type": "string" +} - changed
Input schema / properties / unblocker / descriptionPrevious value: -"Add common browser headers such as User-Agent, Sec-Ch-Ua, and Accept-Encoding. Default false. Enable it for targets that reject basic HTTP requests."New value: +"Send a full browser header set, including User-Agent and Sec-Ch-Ua. Default true. Set false for a plain HTTP request; profile selection needs it on and errors when it is off." - added
Input schema / properties / versionAdded value: +{ + "description": "Browser version to present, as listed in the catalogue. The newest match wins when several fit. An impossible combination returns an error listing what is available; no other browser is substituted.", + "type": "string" +} - added
Output schema / properties / defenseAdded value: +{ + "additionalProperties": {}, + "description": "Present when the target ran a bot check. When solved is false the body may be a challenge page: retry with a different browser, os, or version, or move to foura_proxy or foura_browser.", + "properties": { + "solved": { + "description": "True when the check was met and `data` is the real page.", + "type": "boolean" + } + }, + "type": "object" +}
4 tool updates
v0.5.0- Changed
foura_auto30 fields changed- changed
Input schema / properties / followRedirects / descriptionPrevious value: -"Follow up to N redirects on the cheap (direct / proxy) rungs so a 301/302 lands on the real content instead of being returned as-is. Default 5; 0 = don't follow. The browser rung follows redirects natively."New value: +"Follow up to N redirects for HTTP and proxy requests. Default 5; 0 means don't follow. Browser navigation handles redirects itself." - changed
Input schema / properties / forceProxy / descriptionPrevious value: -"Always reach the target through a rotating proxy, never from FourA's own egress. Default true (the target never sees FourA's origin IP). Send false to allow the cheaper direct path - but note some trust-gated defenses actually resolve more easily from the direct egress, so forcing a proxy can make those targets harder (more attempts / credits)."New value: +"Require proxy routing for every target request. Default true. Send false to allow direct HTTP when suitable." - changed
Input schema / properties / headers / descriptionPrevious value: -"Custom HTTP headers to send to the TARGET, as [name, value] tuples. Example: [[\"Accept\", \"application/json\"], [\"Authorization\", \"Bearer ...\"]]"New value: +"Custom HTTP headers as [name, value] tuples. Example: [[\"Accept\", \"application/json\"], [\"Authorization\", \"Bearer ...\"]]" - changed
Input schema / properties / ignoreProxies / descriptionPrevious value: -"Exits to AVOID - base36 proxy ids (like \"4DZ3VE\") or proxy URLs. Auto skips a warm session on one of these and tells its internal proxy search to avoid them too. Use to rotate away from an exit that just got blocked."New value: +"Exits to avoid - base36 proxy IDs (like \"4DZ3VE\") or proxy URLs. Use this to rotate away from an exit that was just blocked." - changed
Input schema / properties / offload_large / descriptionPrevious value: -"If true, response bodies >= 50KB are written to disk and returned as a resource_link instead of inlined. Saves token context but requires a client that supports `resources/read`. Default false."New value: +"If true, response bodies of 50 KB or more are returned as a resource_link instead of inlined. Default false. Read the returned offloaded_resource_uri with resources/read." - changed
Input schema / properties / returnSession / descriptionPrevious value: -"Return the {proxy, cookies, userAgent} session triple of the winning session so you can replay it through foura_single / foura_proxy later. Default true. Send false for a leaner response when you only need the content."New value: +"Return reusable {proxy, cookies, userAgent} values for follow-up calls. Default true. Send false for a leaner response when you only need the content." - changed
Input schema / properties / timeout_ms / descriptionPrevious value: -"Total time budget in ms for the WHOLE operation - auto fires several internal attempts and they must all fit inside this. Default 120000, max 180000. Auto portions the budget across its attempts; it does not hand the whole budget to one attempt."New value: +"Total time budget in ms for the whole operation. Every attempt must fit inside it. Default 120000, max 180000." - changed
Input schema / properties / url / descriptionPrevious value: -"Target URL. Public hosts only - private/reserved ranges (RFC 1918 10/8, 172.16/12, 192.168/16, loopback 127/8, link-local, IPv6 ULA fc00::/7, IPv6 loopback ::1, plus *.local mDNS) are refused with code `ssrf_blocked`. Example: https://example.com/page. Use {ts} anywhere in the URL to insert the current Unix timestamp for cache-bust."New value: +"Public target URL. Private or reserved targets return `ssrf_blocked`. Use {ts} in the URL to insert the current Unix timestamp. Example: https://example.com/page." - added
Input schema / properties / validate / descriptionAdded value: +"Post-fetch response validation. When the response fails these checks foura_auto returns an error envelope." - added
Input schema / properties / validate / properties / data / descriptionAdded value: +"Body validation: pass when the body contains an expected substring (accept), fail when it contains a blocked one (fail)." - changed
Input schema / properties / validate / properties / data / properties / accept / descriptionPrevious value: -"Substrings the final body MUST contain for the fetch to count as solved (CASE-SENSITIVE). Strongly recommended on protected targets so auto can tell a real page from a challenge page."New value: +"Case-sensitive substrings the final body must contain. Use this on protected targets to distinguish the real page from a challenge page." - changed
Input schema / properties / validate / properties / data / properties / fail / descriptionPrevious value: -"Substrings the final body must NOT contain"New value: +"Substrings the final body must not contain" - added
Input schema / properties / validate / properties / headers / descriptionAdded value: +"Header validation: pass when an accepted header matches, fail when a blocklisted header matches." - changed
Input schema / properties / validate / properties / headers / properties / accept / descriptionPrevious value: -"Map of header-name-substring → header-value-substring (case-insensitive). PASSES if at least one entry matches a response header."New value: +"Case-insensitive header substring rules. The response passes when at least one name/value pair matches." - changed
Input schema / properties / validate / properties / headers / properties / fail / descriptionPrevious value: -"Map of header-name-substring → header-value-substring (case-insensitive). FAILS if any entry matches a response header (use to reject challenge / block headers)."New value: +"Case-insensitive header substring rules that reject the response when any name/value pair matches." - added
Input schema / properties / validate / properties / status / descriptionAdded value: +"Status-code validation: which HTTP status codes count as success (accept) or failure (fail)." - changed
Output schema / properties / attempts / descriptionPrevious value: -"Total sub-call attempts when the ladder failed (also present inside `meta`)."New value: +"Total attempts when the request failed (also present inside `meta`)." - changed
Output schema / properties / code / descriptionPrevious value: -"Stable error code for retry classification. One of: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), auth_failed (401), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive)."New value: +"Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. Other codes: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive)." - changed
Output schema / properties / error / descriptionPrevious value: -"Human-readable error message when the ladder could not deliver the content within the budget."New value: +"Human-readable error message when the request could not deliver content within the budget." - changed
Output schema / properties / headers / descriptionPrevious value: -"Response headers from the delivering rung, as an array of objects. Each entry has `result.{version, code, reason}` plus arbitrary header-name keys whose values are strings (or arrays of strings for multi-value headers like Set-Cookie / Link). Last array entry is the final response."New value: +"Response headers from the successful request, as an array of objects. Each entry has `result.{version, code, reason}` plus header-name keys. The last entry is the final response." - changed
Output schema / properties / meta / descriptionPrevious value: -"Trace of what the ladder did: rung, solved, attempts, credits. Always present."New value: +"Completion details: rung, solved, attempts, and credits. Always present." - changed
Output schema / properties / meta / properties / attempts / descriptionPrevious value: -"Total internal sub-call attempts across the whole ladder."New value: +"Total fetch attempts made for this request." - changed
Output schema / properties / meta / properties / credits / descriptionPrevious value: -"Total credits spent (sum of every internal sub-call). A cold solve is expensive; a subsequent warm replay amortizes to the cheap-fetch cost."New value: +"Total credits spent across all attempts." - changed
Output schema / properties / meta / properties / rung / descriptionPrevious value: -"Which rung delivered the content (e.g. probe / proxy / browser / cache). `cache` means a warm session was replayed cheaply."New value: +"Which method delivered the content (e.g. probe / proxy / browser / cache). `cache` means a reusable session was used." - changed
Output schema / properties / offloaded_resource_uri / descriptionPrevious value: -"foura-mcp://payload/<uuid>"New value: +"foura-mcp://payload/<uuid>. Pass this URI to resources/read to retrieve the offloaded body." - changed
Output schema / properties / retryAfter / descriptionPrevious value: -"Seconds to wait before retrying (429/503 from the gateway)"New value: +"Seconds to wait before retrying a 429 or 503 response" - changed
Output schema / properties / session / descriptionPrevious value: -"The {proxy, cookies, userAgent} triple of the winning session, for DIY replay through foura_single / foura_proxy. Present by default (send returnSession:false to omit)."New value: +"Reusable {proxy, cookies, userAgent} values for follow-up calls. For plain HTTP, call foura_single with session.proxy as proxy, session.userAgent as a User-Agent header, and session.cookies serialized as a Cookie header. For JavaScript, pass the three values to foura_browser fields. Present by default; send returnSession:false to omit." - changed
Output schema / properties / session / properties / cookies / descriptionPrevious value: -"Cookies accumulated by the winning session - replay them on a follow-up request."New value: +"Cookie objects accumulated by the winning session. For foura_single, serialize their name/value pairs into a Cookie header; pass the array directly to foura_browser.cookies." - changed
Output schema / properties / session / properties / userAgent / descriptionPrevious value: -"User-Agent string the winning session used - send the same one when replaying."New value: +"User-Agent used by the winning session. Send it as a User-Agent header to foura_single or as foura_browser.userAgent." - changed
Output schema / properties / status / descriptionPrevious value: -"HTTP status code from the target on the rung that delivered the content. `0` indicates the whole ladder failed before any HTTP response - check `error`."New value: +"HTTP status code from the request that delivered the content. `0` means no HTTP response was received; check `error`."
- Changed
foura_browser13 fields changed- changed
Input schema / properties / checkStatus / descriptionPrevious value: -"Expected HTTP status code. If the page returns a different status → tool returns an error envelope with the actual status carried in the envelope. Example: 200 for product pages, or 404 to assert a soft-404 didn't leak through."New value: +"Expected HTTP status code. A different status returns an error envelope carrying the actual value. Example: 200 for a product page." - changed
Input schema / properties / checkText / descriptionPrevious value: -"One-shot post-render validator - substring search on the rendered HTML AFTER navigation completes. NOT a waiter: does not poll, does not block until the substring appears. If the substring is missing, the tool returns an error envelope. Use to catch silent failures like a 200 response that captured a challenge page or empty SPA shell. Example: \"add to cart\" for product pages."New value: +"Validate the rendered HTML once navigation completes. This is a substring check, not a waiter, and it doesn't poll. A missing substring returns an error envelope. Example: \"add to cart\" for a product page." - added
Input schema / properties / cookies / items / properties / domain / descriptionAdded value: +"Cookie domain (e.g. .example.com). Omit to scope it to the navigated URL's host." - added
Input schema / properties / cookies / items / properties / name / descriptionAdded value: +"Cookie name." - added
Input schema / properties / cookies / items / properties / value / descriptionAdded value: +"Cookie value." - changed
Input schema / properties / headers / descriptionPrevious value: -"Custom HTTP headers as a key-value object (NOT [name, value] tuples). Example: {\"Referer\": \"https://google.com/\"}"New value: +"Custom HTTP headers as a key-value object rather than [name, value] tuples. Example: {\"Referer\": \"https://google.com/\"}" - changed
Input schema / properties / offload_large / descriptionPrevious value: -"If true, response bodies >= 50KB are written to disk and returned as a resource_link instead of inlined. Default false."New value: +"If true, response bodies of 50 KB or more are returned as a resource_link instead of inlined. Default false. Read the returned offloaded_resource_uri with resources/read." - changed
Input schema / properties / proxy / descriptionPrevious value: -"Optional proxy. Three forms: (1) URL `http://user:pass@host:port` or `socks5://host:port`; (2) base36 ID from foura_proxy (e.g. `4DZ3VE`) - same pool exit IP; (3) omit → fixed container egress."New value: +"Optional proxy. Three forms: (1) URL `http://user:pass@host:port` or `socks5://host:port`; (2) base36 ID from foura_proxy (e.g. `4DZ3VE`) to reuse the same exit; (3) omit to use the default route." - changed
Input schema / properties / unblocker / descriptionPrevious value: -"Actively SOLVE an anti-bot / captcha challenge (Cloudflare Turnstile and similar) encountered during navigation, instead of just rendering it. Default true. Set false to render and return the page exactly as it loads - including a challenge page - without attempting to solve; cheaper when you already know the target is open or you want the raw challenge page."New value: +"Handle supported anti-bot or captcha challenges during navigation. Default true. Set false to return the page exactly as it loads, including any challenge page." - changed
Input schema / properties / url / descriptionPrevious value: -"Target URL to load in a full browser session. Public hosts only - private/reserved ranges (RFC 1918 + loopback + link-local + IPv6 ULA/loopback + *.local mDNS) are refused with code `ssrf_blocked`. Example: https://shop.example.com/product/123 or any single-page-app URL."New value: +"Public URL to load in a full browser session. Private or reserved targets return `ssrf_blocked`. Example: https://shop.example.com/product/123." - changed
Output schema / properties / code / descriptionPrevious value: -"Stable error code for retry classification. One of: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), auth_failed (401), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive)."New value: +"Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. Other codes: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive)." - changed
Output schema / properties / cookies / descriptionPrevious value: -"Full cookie objects collected after navigation (name, value, domain, path, expires, httpOnly, secure, session, sameSite, …)"New value: +"Full cookie objects collected after navigation, including name, value, domain, path, expiry, and same-site settings." - changed
Output schema / properties / offloaded_resource_uri / descriptionPrevious value: -"foura-mcp://payload/<uuid>"New value: +"foura-mcp://payload/<uuid>. Pass this URI to resources/read to retrieve the offloaded body."
- Changed
foura_proxy26 fields changed- added
Input schema / properties / exitCountriesAdded value: +{ + "description": "Optional target-visible proxy countries as two-letter provider codes, for example [\"CZ\", \"GB\"]. Use codes supplied by the user or target requirements. When geography matters, do not guess codes or substitute unscoped rotation. Values are trimmed, uppercased, and deduplicated. Unknown exits are excluded and the request never falls back to another country.", + "items": { + "pattern": "^[A-Z]{2}$", + "type": "string" + }, + "minItems": 1, + "type": "array" +} - changed
Input schema / properties / ignoreProxies / descriptionPrevious value: -"Encoded proxy IDs (base36 strings like \"4DZ3VE\") OR proxy URLs to exclude from rotation. Both forms are accepted."New value: +"Encoded proxy IDs (base36 strings like \"4DZ3VE\") or proxy URLs to exclude from rotation." - changed
Input schema / properties / maxTries / descriptionPrevious value: -"Maximum proxy rotation attempts before giving up (default 5, max 90). Default 5 is sized for lightly-blocked sites. Raise to 25-30 for tier-1 WAF challenges (Vercel Security Checkpoint, Cloudflare 'Just a moment', Akamai Bot Manager) - most rotations on these targets need this range. If still blocked after 30 attempts, the gate is likely country / ASN allowlist (not solvable by rotation) - pivot strategy instead of climbing to 60."New value: +"Maximum rotation attempts before giving up (default 5, max 90). Difficult protected targets may need 25-30. Use exitCountries for country scope." - changed
Input schema / properties / offload_large / descriptionPrevious value: -"If true, response bodies >= 50KB are written to disk and returned as a resource_link instead of inlined. Default false."New value: +"If true, response bodies of 50 KB or more are returned as a resource_link instead of inlined. Default false. Read the returned offloaded_resource_uri with resources/read." - added
Input schema / properties / request / properties / accept_timeout_ms / descriptionAdded value: +"Timeout in ms to receive the first response byte after the request is sent (0-120000). Omit for the default." - added
Input schema / properties / request / properties / connect_timeout_ms / descriptionAdded value: +"Timeout in ms for establishing the connection to the target through the proxy (0-120000). Omit for the default." - added
Input schema / properties / request / properties / dns_cache_timeout_sec / descriptionAdded value: +"How long (seconds) to cache the target's resolved DNS (0-240). Omit for the default." - changed
Input schema / properties / request / properties / headers / descriptionPrevious value: -"Custom HTTP headers as [name, value] tuples. Example: "New value: +"Custom HTTP headers as [name, value] tuples. Example: [[\"Accept\", \"application/json\"]]" - added
Input schema / properties / request / properties / returnBuffer / descriptionAdded value: +"Return raw bytes as a serialized Buffer JSON shape ({type:\"Buffer\", data:[byte, ...]}) instead of a decoded string. Use for binary responses (images, protobuf)." - added
Input schema / properties / request / properties / server_response_timeout_ms / descriptionAdded value: +"Timeout in ms for the server to send the complete response (0-120000). Omit for the default." - added
Input schema / properties / request / properties / tryJsonData / descriptionAdded value: +"If true, attempt JSON.parse on the response body; on success `data` is the parsed value, otherwise it stays the original string. Omit to keep the body as-is." - changed
Input schema / properties / request / properties / unblocker / descriptionPrevious value: -"Inject realistic browser headers (User-Agent, Sec-Ch-Ua, Accept-Encoding, …) and make the request look like it's coming from a real browser at the wire level. Default false - STRONGLY recommended on proxy paths since most sites that need a proxy also have wire-level anti-bot (Cloudflare, Akamai, PerimeterX, Datadome). Cheap to leave on for production scrapes."New value: +"Add common browser headers such as User-Agent, Sec-Ch-Ua, and Accept-Encoding. Default false. Enable it for targets that reject basic HTTP requests." - changed
Input schema / properties / request / properties / url / descriptionPrevious value: -"Target URL the proxy should fetch. Public hosts only - private/reserved ranges (RFC 1918 + loopback + link-local + IPv6 ULA/loopback + *.local mDNS) are refused with code `ssrf_blocked`. Example: https://shop.example.com/pricing for blocked sites. {ts} placeholder is replaced with current Unix timestamp."New value: +"Public target URL. Private or reserved targets return `ssrf_blocked`. Use {ts} in the URL to insert the current Unix timestamp. Example: https://shop.example.com/pricing." - added
Input schema / properties / request / properties / validate / descriptionAdded value: +"Per-attempt response validation. A proxy attempt that fails these checks is treated as failed and the next proxy is tried." - added
Input schema / properties / request / properties / validate / properties / data / descriptionAdded value: +"Body validation: pass when the body contains an expected substring (accept), fail when it contains a blocked one (fail)." - added
Input schema / properties / request / properties / validate / properties / data / properties / accept / descriptionAdded value: +"Substrings the response body must contain to pass." - added
Input schema / properties / request / properties / validate / properties / data / properties / fail / descriptionAdded value: +"Substrings that, if present in the body, mark the response as failed." - added
Input schema / properties / request / properties / validate / properties / headers / descriptionAdded value: +"Header validation: pass when an accepted header matches, fail when a blocklisted header matches." - changed
Input schema / properties / request / properties / validate / properties / headers / properties / accept / descriptionPrevious value: -"Map of header-name-substring → header-value-substring (both case-insensitive). Response PASSES if AT LEAST ONE entry matches (header name contains the key AND value contains the value). Checked across all redirect hops. Empty / omitted = no header requirement."New value: +"Case-insensitive header substring rules. The response passes when at least one name/value pair matches across the redirect chain." - changed
Input schema / properties / request / properties / validate / properties / headers / properties / fail / descriptionPrevious value: -"Map of header-name-substring → header-value-substring (both case-insensitive). Response is treated as FAILURE if ANY entry matches a response header. Use to reject challenge / block headers, e.g. {\"x-blocked\": \"bot\", \"server\": \"cloudflare\"}."New value: +"Case-insensitive header substring rules that reject the response when any name/value pair matches." - added
Input schema / properties / request / properties / validate / properties / status / descriptionAdded value: +"Status-code validation: which HTTP status codes count as success (accept) or failure (fail)." - changed
Output schema / properties / code / descriptionPrevious value: -"Stable error code for retry classification. One of: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), auth_failed (401), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive)."New value: +"Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. no_eligible_proxy means the strict exitCountries scope had no match. Keep that scope and retry later; do not propose or perform an unscoped fallback." - added
Output schema / properties / detailsAdded value: +{ + "additionalProperties": false, + "description": "Structured no_eligible_proxy context containing the normalized requested country scope. Preserve this scope and retry later. Do not propose or perform an unscoped fallback; change it only after the user explicitly changes the requirement.", + "properties": { + "exitCountries": { + "items": { + "pattern": "^[A-Z]{2}$", + "type": "string" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "exitCountries" + ], + "type": "object" +} - added
Output schema / properties / exitCountryAdded value: +{ + "description": "Latest available two-letter target-visible exit-country code used for selection. Present on successful requests that use exitCountries.", + "pattern": "^[A-Z]{2}$", + "type": "string" +} - changed
Output schema / properties / offloaded_resource_uri / descriptionPrevious value: -"foura-mcp://payload/<uuid>"New value: +"foura-mcp://payload/<uuid>. Pass this URI to resources/read to retrieve the offloaded body." - changed
Output schema / properties / proxy / descriptionPrevious value: -"Base36 ID of the pool exit that succeeded (e.g. `4DZ3VE`). Reuse on next call: pass to foura_single.proxy or foura_browser.proxy → same exit IP. Pass to foura_proxy.ignoreProxies → skip this exit on future rotations."New value: +"Base36 ID of the exit that succeeded (e.g. `4DZ3VE`). Pass it to foura_single.proxy or foura_browser.proxy to reuse that exit, or to foura_proxy.ignoreProxies to skip it on future rotations."
- Changed
foura_single17 fields changed- added
Input schema / properties / accept_timeout_ms / descriptionAdded value: +"Timeout in ms to receive the first response byte after the request is sent (0-120000). Omit for the default." - added
Input schema / properties / connect_timeout_ms / descriptionAdded value: +"Timeout in ms for establishing the TCP/TLS connection (0-120000). Omit to use the default." - added
Input schema / properties / dns_cache_timeout_sec / descriptionAdded value: +"How long (seconds) to cache the target's resolved DNS (0-240). Omit for the default." - changed
Input schema / properties / offload_large / descriptionPrevious value: -"If true, response bodies >= 50KB are written to disk and returned as a resource_link instead of inlined. Saves token context but requires a client that supports `resources/read`. Default false."New value: +"If true, response bodies of 50 KB or more are returned as a resource_link instead of inlined. Default false. Read the returned offloaded_resource_uri with resources/read." - changed
Input schema / properties / proxy / descriptionPrevious value: -"Optional proxy. Two forms: (1) URL `http://host:port` or `socks5://host:port`; (2) base36 ID from foura_proxy (e.g. `4DZ3VE`) - same exit IP. For rotation, use foura_proxy."New value: +"Optional proxy. Two forms: (1) URL `http://host:port` or `socks5://host:port`; (2) base36 ID from foura_proxy (e.g. `4DZ3VE`) to reuse the same exit. For rotation, use foura_proxy." - added
Input schema / properties / server_response_timeout_ms / descriptionAdded value: +"Timeout in ms for the server to send the complete response (0-120000). Omit for the default." - changed
Input schema / properties / unblocker / descriptionPrevious value: -"Inject realistic browser headers (User-Agent, Sec-Ch-Ua, Accept-Encoding, …) and make the request look like it's coming from a real browser at the wire level. Default false - set true for any target with anti-bot or WAF (Cloudflare, Akamai, PerimeterX, Datadome). Cheap to leave on for production scrapes."New value: +"Add common browser headers such as User-Agent, Sec-Ch-Ua, and Accept-Encoding. Default false. Enable it for targets that reject basic HTTP requests." - changed
Input schema / properties / url / descriptionPrevious value: -"Target URL. Public hosts only - private/reserved ranges (RFC 1918 10/8, 172.16/12, 192.168/16, loopback 127/8, link-local, IPv6 ULA fc00::/7, IPv6 loopback ::1, plus *.local mDNS) are refused with code `ssrf_blocked`. Example: https://example.com/page or https://api.example.com/v1/users. Use {ts} anywhere in the URL to insert current Unix timestamp for cache-bust."New value: +"Public target URL. Private or reserved targets return `ssrf_blocked`. Use {ts} in the URL to insert the current Unix timestamp. Example: https://api.example.com/v1/users." - added
Input schema / properties / validate / descriptionAdded value: +"Post-fetch response validation. When the response fails these checks the tool returns an error envelope." - added
Input schema / properties / validate / properties / data / descriptionAdded value: +"Body validation: pass when the body contains an expected substring (accept), fail when it contains a blocked one (fail)." - changed
Input schema / properties / validate / properties / data / properties / fail / descriptionPrevious value: -"Substrings the response body must NOT contain"New value: +"Substrings the response body must not contain" - added
Input schema / properties / validate / properties / headers / descriptionAdded value: +"Header validation: pass when an accepted header matches, fail when a blocklisted header matches." - changed
Input schema / properties / validate / properties / headers / properties / accept / descriptionPrevious value: -"Map of header-name-substring → header-value-substring (both case-insensitive). Response PASSES if AT LEAST ONE entry matches (header name contains the key AND value contains the value). Checked across all redirect hops. Empty / omitted = no header requirement."New value: +"Case-insensitive header substring rules. The response passes when at least one name/value pair matches across the redirect chain." - changed
Input schema / properties / validate / properties / headers / properties / fail / descriptionPrevious value: -"Map of header-name-substring → header-value-substring (both case-insensitive). Response is treated as FAILURE if ANY entry matches a response header. Use to reject challenge / block headers, e.g. {\"x-blocked\": \"bot\", \"server\": \"cloudflare\"}."New value: +"Case-insensitive header substring rules that reject the response when any name/value pair matches." - added
Input schema / properties / validate / properties / status / descriptionAdded value: +"Status-code validation: which HTTP status codes count as success (accept) or failure (fail)." - changed
Output schema / properties / code / descriptionPrevious value: -"Stable error code for retry classification. One of: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), auth_failed (401), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive)."New value: +"Stable error code for retry classification. auth_failed means the FourA API key was rejected; verify that key, not target-site credentials. Other codes: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive)." - changed
Output schema / properties / offloaded_resource_uri / descriptionPrevious value: -"foura-mcp://payload/<uuid>"New value: +"foura-mcp://payload/<uuid>. Pass this URI to resources/read to retrieve the offloaded body."
4 tool updates
v0.3.2- First observed
foura_auto - First observed
foura_browser - First observed
foura_proxy - First observed
foura_single
TDQS
Scored across 4 tools
Each tool has a clearly distinct purpose: direct request, proxy-routed request, full browser, and automatic escalation. The descriptions explicitly cross-reference when to use each, so an agent should not confuse them.
All tools follow the same foura_<mode> convention using lowercase snake_case. The names are short, consistent, and map directly to the tool's behavior.
Four tools is well-scoped for an HTTP fetching server. Each tool covers a distinct delivery mode and earns its place without redundancy or bloat.
The tool set covers the full spectrum of fetching needs: plain requests, proxy rotation with exit control, JavaScript rendering, and automatic fallback. Descriptions also clarify which limitations push users to another tool, leaving no obvious dead ends for content retrieval.
Maintenance
Related MCP Connectors
One MCP for the Web. Easily search, crawl, navigate, and extract websites without getting blocked.…
One MCP server for 180+ live web-data APIs returning clean JSON from sites that block scrapers.
All HasData scraping tools in one MCP server: Google, TikTok, Instagram, maps, e-commerce and more.
ScrapingBee MCP — wraps the ScrapingBee headless-scraping API (scrapingbee.com)
Related MCP Servers
AlicenseBqualityFmaintenanceA scraper tool that leverages the Oxylabs Web Scraper API to fetch and process web content with flexible options for parsing and rendering pages, enabling efficient content extraction from complex websites.101,462 PyPI106MIT
Bright Data MCPofficial
AlicenseAqualityAmaintenanceOfficial Bright Data server for the Model Context Protocol that enables AI assistants like Claude Desktop to reference and make decisions based on real-time public web data.510,020 npm2,650MIT
zenrows-mcpofficial
AlicenseAqualityCmaintenanceScrape any webpage and return clean markdown, HTML, or structured JSON. Bypasses anti-bot protection, renders JavaScript (React/Vue/Angular), supports premium residential proxies and CSS extraction. Works with any MCP client — no local install required.1635 npm19MIT- AlicenseNot gradedqualityCmaintenanceWeb scraping and search MCP server that wraps Firecrawl API for URL discovery and web search with optional content retrieval.2 npm1MIT