Zenrows MCP server — Fetch, Extract, Batch, and Browser Sessions for AI coding assistants
Zenrows MCP demonstrates solid tool design with comprehensive parameter schemas, clear descriptions, and proper error guidance. All 7 tools have explicit registrations with Zod schemas and detailed descriptions (50-400+ chars). Tool names follow verb_noun convention (scrape, batch_create, batch_status). Parameters are well-typed with enums where appropriate (response_type, status filters). However, output schemas are not documented, LLMs cannot see what fields to expect from responses. Error handling guidance is present in descriptions (e.g., account_usage explains AUTH004/AUTH006 and recovery paths) but not formalized in tool responses. Some parameter descriptions could be more concise; batch_create's description is verbose. No tool annotations for idempotency or confirmation patterns on destructive operations (batch_cancel).
Read the current plan's credit allowance and how much of it is spent. Call this BEFORE a large batch, and after any 402 / AUTH004, to find out whether the account is out of credits and when the allowance renews. It is free and does not consume a concurrency slot, so it is safe to poll between runs. Credit costs per request: 1 basic, 5 js_render, 10 premium_proxy, 25 both. On a small plan a few hundred protected requests can exhaust a month, so check before fanning out. AUTH004 ("usage exceeded") means this allowance is spent. It renews at the end of the billing period, so it is not a permanent block: never retry-loop against it. If the human does not want to wait for the renewal, relay the way to continue now: add a credit pack at https://app.zenrows.com/billing?topup=open (opens the purchase directly) or upgrade at https://app.zenrows.com/plans. Prices are per plan; quote them only from this tool's response, never from memory. AUTH006 is the concurrency limit, which is a different thing entirely.
Stop an in-flight Batch job run (POST /jobs/:id/stop).
Submit a cloud Batch job that fans out many URLs asynchronously (Zenrows Batch API beta). NOT the same as browser_batch — this hits https://async.api.zenrows.com/v1 with X-API-Key. Use for large URL lists; prefer scrape/extract for one-off pages. Returns job_id + latest_run.status/stats. Poll with batch_status / batch_wait, then batch_results. If you get BATCH_ACCESS_DENIED, the account lacks Batch beta access.
Output schemas not documented. LLMs cannot see what fields scrape, batch_results, or account_usage return, forcing them to guess downstream field names and risk broken tool chains.
batch_cancel lacks destructiveHint annotation and no confirmation/dry-run pattern. Agents can stop jobs without warning, risking unintended cancellations of long-running batches.
batch_create's 'wait' parameter defaults to false but description does not explain the polling alternative (batch_wait). Agents may assume the tool blocks until completion, leading to timeout errors.
scrape tool accepts 'screenshot', 'screenshot_fullpage', 'screenshot_selector' but no guidance on when to use each or what format is returned (base64, URL, file path). LLMs will guess.
Inferred effective spec: 2026-07-28+.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | B | 70 | 2026-07-28+ | v2 |
List result rows for a Batch job (cursor-paginated server-side; returns the full list). Each row may include task_id, external_id, status, and a short-lived result_url for the body. Download result_url soon — presigned links expire.
Get status and stats for a Zenrows Batch job (latest_run.status + latest_run.stats).
Poll batch_status until the job reaches a terminal state (completed, stopped, or deleted).
Scrape any webpage and return its content using Zenrows (Fetch). Use for full-page content (markdown/HTML/PDF/screenshot). For structured JSON fields (products, articles, listings), prefer the extract tool when it fits — it returns parsed fields instead of a full page body. When to enable options: - js_render: page uses React/Vue/Angular, loads content dynamically, or content appears missing on the first attempt - premium_proxy: site returns 403/blocked errors even with js_render enabled - wait_for: specific content loads after initial render (requires js_render) Examples: Basic: { url: "https://example.com" } Dynamic: { url: "https://spa.com", js_render: true } Protected:{ url: "https://protected.com", js_render: true, premium_proxy: true }
batch_results returns 'result_url' with presigned links that expire, but no guidance on how quickly to download or what to do if expired. Agents may lose data.