Skip to main content
Glama
alterlab-mcp-server

alterlab-mcp-server

alterlab_batch

Start an asynchronous batch scrape for up to 100 URLs and retrieve results later via batch ID, with per-URL modes, formats, and extraction schemas to handle blocked or JavaScript-heavy pages.

Instructions

Start an asynchronous batch job for a large URL set (up to 100 per call) and poll for results later. Use when a normal fetch returns 403/429, a bot-protection challenge page, a CAPTCHA, or an empty JavaScript shell. Each URL can have its own mode, formats and extraction_schema. Returns a batch_id immediately; results are available from GET /api/v1/batch/{batch_id}.

Input Schema

NameRequiredDescriptionDefault
urlsYesList of URLs to scrape (max 100)
exportNoExport batch results to a storage integration when the batch finishes
session_idNoUUID of a stored session applied to every URL in the batch (see alterlab_list_sessions)
webhook_urlNoWebhook URL to receive batch.completed event when all jobs finish
extraction_promptNoBatch-level natural language extraction instruction
extraction_schemaNoBatch-level JSON schema for structured extraction applied to every URL
extraction_profileNoBatch-level pre-built extraction profile applied to every URL
extraction_providerNoBatch-level BYOK LLM provider for extraction

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed30 schema fields changedv1.9.0
    • addedInput schema / properties / export
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "Export batch results to a storage integration when the batch finishes",
      +  "properties": {
      +    "format": {
      +      "description": "Export file format (API default jsonl)",
      +      "enum": [
      +        "jsonl",
      +        "csv",
      +        "json"
      +      ],
      +      "type": "string"
      +    },
      +    "integration_id": {
      +      "description": "ID of a storage integration (S3/R2/GCS) configured in the dashboard",
      +      "type": "string"
      +    },
      +    "prefix": {
      +      "description": "Object key prefix for exported files",
      +      "maxLength": 500,
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "integration_id"
      +  ],
      +  "type": "object"
      +}
    • addedInput schema / properties / extraction_profile
      Added value: +{
      +  "description": "Batch-level pre-built extraction profile applied to every URL",
      +  "enum": [
      +    "auto",
      +    "product",
      +    "article",
      +    "job_posting",
      +    "faq",
      +    "recipe",
      +    "event"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / extraction_prompt
      Added value: +{
      +  "description": "Batch-level natural language extraction instruction",
      +  "maxLength": 2000,
      +  "type": "string"
      +}
    • addedInput schema / properties / extraction_provider
      Added value: +{
      +  "$ref": "#/properties/urls/items/properties/extraction_provider",
      +  "description": "Batch-level BYOK LLM provider for extraction"
      +}
    • addedInput schema / properties / extraction_schema
      Added value: +{
      +  "additionalProperties": {},
      +  "description": "Batch-level JSON schema for structured extraction applied to every URL",
      +  "type": "object"
      +}
    • addedInput schema / properties / session_id
      Added value: +{
      +  "description": "UUID of a stored session applied to every URL in the batch (see alterlab_list_sessions)",
      +  "format": "uuid",
      +  "type": "string"
      +}
    • addedInput schema / properties / urls / items / properties / advanced
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "Advanced scrape options for this URL (render_js, use_proxy, use_own_proxy, actions, session_id, cookies, skip_tls_verification, sticky_session, ...). Same fields as the alterlab_scrape parameters of the same name.",
      +  "properties": {
      +    "actions": {
      +      "description": "Browser automation actions run in order after page load (max 20, requires render_js=true). Failed actions are skipped without aborting the sequence. Results are returned in action_results. Each action has a 'type': wait, wait_for, click, fill, press, scroll, infinite_scroll, screenshot, evaluate.",
      +      "items": {
      +        "anyOf": [
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "milliseconds": {
      +                "maximum": 30000,
      +                "minimum": 100,
      +                "type": "integer"
      +              },
      +              "selector": {
      +                "description": "CSS selector to wait for visibility",
      +                "maxLength": 500,
      +                "type": "string"
      +              },
      +              "type": {
      +                "const": "wait",
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "type"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "selector": {
      +                "maxLength": 500,
      +                "type": "string"
      +              },
      +              "timeout": {
      +                "description": "Timeout in ms (default 10000)",
      +                "maximum": 30000,
      +                "minimum": 1000,
      +                "type": "integer"
      +              },
      +              "type": {
      +                "const": "wait_for",
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "type",
      +              "selector"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "selector": {
      +                "maxLength": 500,
      +                "type": "string"
      +              },
      +              "type": {
      +                "const": "click",
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "type",
      +              "selector"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "selector": {
      +                "maxLength": 500,
      +                "type": "string"
      +              },
      +              "type": {
      +                "const": "fill",
      +                "type": "string"
      +              },
      +              "value": {
      +                "maxLength": 5000,
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "type",
      +              "selector",
      +              "value"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "key": {
      +                "description": "Key to press, e.g. 'Enter', 'Tab', 'Escape'",
      +                "maxLength": 50,
      +                "type": "string"
      +              },
      +              "type": {
      +                "const": "press",
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "type",
      +              "key"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "amount": {
      +                "description": "Viewport heights to scroll",
      +                "maximum": 20,
      +                "minimum": 1,
      +                "type": "integer"
      +              },
      +              "direction": {
      +                "enum": [
      +                  "down",
      +                  "up"
      +                ],
      +                "type": "string"
      +              },
      +              "type": {
      +                "const": "scroll",
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "type"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "delay": {
      +                "description": "Delay between scrolls in ms",
      +                "maximum": 5000,
      +                "minimum": 200,
      +                "type": "integer"
      +              },
      +              "end_selector": {
      +                "description": "Stop scrolling when this selector appears",
      +                "maxLength": 500,
      +                "type": "string"
      +              },
      +              "max_scrolls": {
      +                "maximum": 50,
      +                "minimum": 1,
      +                "type": "integer"
      +              },
      +              "type": {
      +                "const": "infinite_scroll",
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "type"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "full_page": {
      +                "type": "boolean"
      +              },
      +              "type": {
      +                "const": "screenshot",
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "type"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "script": {
      +                "description": "JavaScript to run in the page (max 5120 chars). Network APIs (fetch, XMLHttpRequest, WebSocket) and dynamic code execution (eval, Function) are blocked.",
      +                "maxLength": 5120,
      +                "type": "string"
      +              },
      +              "type": {
      +                "const": "evaluate",
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "type",
      +              "script"
      +            ],
      +            "type": "object"
      +          }
      +        ]
      +      },
      +      "maxItems": 20,
      +      "type": "array"
      +    },
      +    "block_images": {
      +      "description": "Block image downloads during browser rendering. Reduces proxy bandwidth and speeds up scrapes. Only effective with render_js=true.",
      +      "type": "boolean"
      +    },
      +    "cookies": {
      +      "additionalProperties": {
      +        "type": "string"
      +      },
      +      "description": "Inline cookies as key-value pairs for authenticated scraping (e.g., {\"session_token\": \"abc123\"}). Use this for one-off requests; use session_id for reusable sessions.",
      +      "type": "object"
      +    },
      +    "flatten_shadow_dom": {
      +      "description": "Flatten Shadow DOM roots into regular DOM for extraction (free, requires render_js).",
      +      "type": "boolean"
      +    },
      +    "generate_pdf": {
      +      "description": "Generate a PDF of the rendered page (+$0.0004, requires render_js)",
      +      "type": "boolean"
      +    },
      +    "include_iframes": {
      +      "description": "Inline iframe content into the main document (free, requires render_js). Same-origin iframes are read directly; cross-origin iframes are marked but not fetched.",
      +      "type": "boolean"
      +    },
      +    "markdown": {
      +      "description": "Extract content as Markdown for this URL (free)",
      +      "type": "boolean"
      +    },
      +    "ocr": {
      +      "description": "Extract text from images using OCR (+$0.001)",
      +      "type": "boolean"
      +    },
      +    "proxy_country": {
      +      "description": "ISO country code for proxy geo-targeting (e.g., 'US', 'DE'). Requires use_proxy=true",
      +      "type": "string"
      +    },
      +    "proxy_integration_id": {
      +      "description": "Specific proxy integration ID to use (requires use_own_proxy=true)",
      +      "type": "string"
      +    },
      +    "remove_cookie_banners": {
      +      "description": "Remove cookie consent banners from HTML before content extraction (free; the API default is true)",
      +      "type": "boolean"
      +    },
      +    "render_js": {
      +      "anyOf": [
      +        {
      +          "type": "boolean"
      +        },
      +        {
      +          "const": "auto",
      +          "type": "string"
      +        }
      +      ],
      +      "description": "Render JavaScript using a headless browser (forces Tier 4 minimum, $0.004/req — no separate add-on charge). Required for JS-heavy sites. Set to 'auto' for smart detection (probes each page, only renders JS-heavy pages with a browser — saves 30-60% on mixed sites)."
      +    },
      +    "screenshot": {
      +      "description": "Capture a full-page screenshot of this URL (+$0.0002, requires render_js)",
      +      "type": "boolean"
      +    },
      +    "scroll_count": {
      +      "description": "Number of scroll iterations when scroll_to_load is enabled (1-10, API default 3)",
      +      "maximum": 10,
      +      "minimum": 1,
      +      "type": "integer"
      +    },
      +    "scroll_to_load": {
      +      "description": "Scroll page to trigger lazy-loaded content (requires render_js). Performs explicit viewport-height scrolls to load dynamic content. Adds ~2-3s latency.",
      +      "type": "boolean"
      +    },
      +    "section_filter": {
      +      "additionalProperties": false,
      +      "description": "Filter for the json_v2 section tree. Only applies when 'json_v2' is in formats.",
      +      "properties": {
      +        "content_only": {
      +          "type": "boolean"
      +        },
      +        "exclude_content_types": {
      +          "items": {
      +            "type": "string"
      +          },
      +          "type": "array"
      +        },
      +        "min_content_blocks": {
      +          "minimum": 0,
      +          "type": "integer"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "session_headers": {
      +      "additionalProperties": {
      +        "type": "string"
      +      },
      +      "description": "Inline auth headers sent to the target (e.g. Authorization: Bearer ...). Merged with the stored session's headers when session_id is also set.",
      +      "type": "object"
      +    },
      +    "session_id": {
      +      "description": "UUID of a stored session for authenticated scraping. Use alterlab_list_sessions to find available sessions. The session's cookies will be injected into the request.",
      +      "format": "uuid",
      +      "type": "string"
      +    },
      +    "skip_tls_verification": {
      +      "description": "TLS certificate verification for the target. Omit (recommended): certificates are verified, and if the site's own certificate is invalid (expired, self-signed, wrong hostname, incomplete chain) the page is still fetched without verification. true skips verification from the start. false always requires a valid certificate, so sites with an invalid certificate fail.",
      +      "type": "boolean"
      +    },
      +    "sticky_session": {
      +      "description": "Sticky-session handle. Scrapes that pass the same value reuse the cookie jar captured on the first call and, best-effort, the same exit IP (~10 min). Alphanumeric, '-' and '_' only. Requires a paid plan (growth tier or above).",
      +      "maxLength": 128,
      +      "type": "string"
      +    },
      +    "sticky_session_ttl": {
      +      "description": "Sticky-session cookie-jar lifetime in seconds (300-7200, API default 1800). Ignored unless sticky_session is set.",
      +      "maximum": 7200,
      +      "minimum": 300,
      +      "type": "integer"
      +    },
      +    "use_own_proxy": {
      +      "description": "Use your own proxy integration (bring-your-own-proxy) instead of the system proxy. BYOP requests get a 20% discount on the tier price.",
      +      "type": "boolean"
      +    },
      +    "use_proxy": {
      +      "description": "Route through AlterLab's premium proxy (+$0.0002). Helps bypass geo-restrictions and anti-bot",
      +      "type": "boolean"
      +    },
      +    "use_system_proxy": {
      +      "description": "Override your default proxy integration and use AlterLab's system proxy for this request.",
      +      "type": "boolean"
      +    },
      +    "wait_condition": {
      +      "description": "Wait condition for JS rendering: domcontentloaded, networkidle or load",
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedInput schema / properties / urls / items / properties / body
      Added value: +{
      +  "description": "Request body for POST requests to this URL",
      +  "type": "string"
      +}
    • removedInput schema / properties / urls / items / properties / cache / default
      Removed value: -false
    • addedInput schema / properties / urls / items / properties / content_type
      Added value: +{
      +  "description": "Content-Type of the POST body for this URL",
      +  "enum": [
      +    "application/json",
      +    "application/x-www-form-urlencoded",
      +    "text/plain",
      +    "application/graphql"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / urls / items / properties / cost_controls
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "Cost and tier controls for this URL (max_tier, force_tier, max_credits, ...)",
      +  "properties": {
      +    "fail_fast": {
      +      "description": "Return error instead of escalating to more expensive tiers on failure.",
      +      "type": "boolean"
      +    },
      +    "force_tier": {
      +      "description": "Pin execution to this exact tier, bypassing escalation (1=curl $0.0002, 2=http $0.0003, 3=stealth $0.002, 3.5=lightjs $0.0025, 4=browser $0.004). Use to guarantee a specific engine is used regardless of site difficulty.",
      +      "enum": [
      +        "1",
      +        "2",
      +        "3",
      +        "3.5",
      +        "4"
      +      ],
      +      "type": "string"
      +    },
      +    "max_credits": {
      +      "description": "Hard spending cap for this request in credits. Request fails if cost would exceed this.",
      +      "exclusiveMinimum": 0,
      +      "type": "number"
      +    },
      +    "max_tier": {
      +      "$ref": "#/properties/urls/items/properties/cost_controls/properties/force_tier",
      +      "description": "Cap automatic escalation at this tier. Scrape will not escalate beyond it even if lower tiers fail. Cannot exceed force_tier when both are set. Combining render_js=true with a max_tier below 4 is rejected (render_js forces tier 4)."
      +    },
      +    "prefer_cost": {
      +      "description": "Optimize for cost — try cheaper tiers first, accept lower success probability.",
      +      "type": "boolean"
      +    },
      +    "prefer_speed": {
      +      "description": "Optimize for speed — skip to the most reliable tier for this domain.",
      +      "type": "boolean"
      +    },
      +    "time_budget": {
      +      "description": "Total wall-clock budget in seconds for the entire tier escalation sequence (5–300s). Escalation stops when remaining budget is insufficient for the next tier attempt.",
      +      "maximum": 300,
      +      "minimum": 5,
      +      "type": "number"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedInput schema / properties / urls / items / properties / extraction_profile
      Added value: +{
      +  "description": "Pre-built extraction profile for this URL (mutually exclusive with extraction_template)",
      +  "enum": [
      +    "auto",
      +    "product",
      +    "article",
      +    "job_posting",
      +    "faq",
      +    "recipe",
      +    "event",
      +    "ecommerce_homepage",
      +    "directory_listing"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / urls / items / properties / extraction_prompt
      Added value: +{
      +  "description": "Natural language extraction instruction for this URL",
      +  "maxLength": 2000,
      +  "type": "string"
      +}
    • addedInput schema / properties / urls / items / properties / extraction_provider
      Added value: +{
      +  "description": "BYOK LLM provider for extraction on this URL",
      +  "enum": [
      +    "openai",
      +    "anthropic",
      +    "openrouter",
      +    "groq"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / urls / items / properties / extraction_template
      Added value: +{
      +  "$ref": "#/properties/urls/items/properties/extraction_profile",
      +  "description": "Alias for extraction_profile (mutually exclusive with it)"
      +}
    • changedInput schema / properties / urls / items / properties / formats / description
      Previous value: -"Output formats for this URL (overrides batch-level formats)"New value: +"Output formats for this URL. 'markdown' is best for LLM consumption. 'json_v2' returns a structured section tree (headings + content blocks). 'rag' returns chunked text optimized for retrieval-augmented generation. 'raw' returns the raw response body without extraction. 'content' returns body_markdown + content_hash + images + links for AI/KB pipelines."
    • changedInput schema / properties / urls / items / properties / formats / items / enum
      Previous value: -[
      -  "text",
      -  "json",
      -  "json_v2",
      -  "html",
      -  "markdown",
      -  "rag"
      -]New value: +[
      +  "text",
      +  "json",
      +  "json_v2",
      +  "html",
      +  "markdown",
      +  "rag",
      +  "content",
      +  "raw"
      +]
    • addedInput schema / properties / urls / items / properties / include_raw_html
      Added value: +{
      +  "description": "Include raw HTML in the result for this URL",
      +  "type": "boolean"
      +}
    • addedInput schema / properties / urls / items / properties / location
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "Geo-targeting for this URL (country, language)",
      +  "properties": {
      +    "country": {
      +      "description": "ISO 3166-1 alpha-2 country code for geo-targeting (e.g., 'US', 'DE', 'JP'). Routes request through a proxy in the specified country.",
      +      "maxLength": 2,
      +      "minLength": 2,
      +      "type": "string"
      +    },
      +    "language": {
      +      "description": "ISO 639-1 language code (e.g., 'en', 'de', 'ja'). Sets the Accept-Language header and browser locale.",
      +      "maxLength": 5,
      +      "minLength": 2,
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedInput schema / properties / urls / items / properties / method
      Added value: +{
      +  "description": "HTTP method for this URL. POST costs 1.5x the base tier price.",
      +  "enum": [
      +    "GET",
      +    "POST"
      +  ],
      +  "type": "string"
      +}
    • removedInput schema / properties / urls / items / properties / mode / default
      Removed value: -"auto"
    • changedInput schema / properties / urls / items / properties / mode / description
      Previous value: -"Scraping mode for this URL"New value: +"Scraping mode for this URL (API default auto)"
    • addedInput schema / properties / urls / items / properties / render_js / anyOf
      Added value: +[
      +  {
      +    "type": "boolean"
      +  },
      +  {
      +    "const": "auto",
      +    "type": "string"
      +  }
      +]
    • changedInput schema / properties / urls / items / properties / render_js / description
      Previous value: -"Render JavaScript for this URL"New value: +"Shortcut for advanced.render_js for this URL"
    • removedInput schema / properties / urls / items / properties / render_js / type
      Removed value: -"boolean"
    • removedInput schema / properties / urls / items / properties / timeout / default
      Removed value: -90
    • changedInput schema / properties / urls / items / properties / timeout / description
      Previous value: -"Timeout in seconds for this URL"New value: +"Timeout in seconds for this URL (1-300, API default 90)"
    • addedInput schema / properties / urls / items / properties / url / maxLength
      Added value: +2083
    • changedInput schema / properties / urls / items / properties / use_proxy / description
      Previous value: -"Use premium proxy for this URL"New value: +"Shortcut for advanced.use_proxy for this URL"
    • addedInput schema / properties / webhook_url / maxLength
      Added value: +2083
  2. First observedv1.5.0

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does reasonably well: it discloses that the operation is asynchronous, returns immediately with a batch_id rather than results, and that results must be polled from GET /api/v1/batch/{batch_id}. Gaps remain around partial-failure behavior, cost implications, and rate limits for a 100-URL job.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four sentences, front-loaded with the core action and scope, then usage trigger, then per-URL nuance, then return semantics. No filler and nothing redundant given the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an async tool with 8 params, heavy nesting, and no output schema, the description covers the essential lifecycle (submit → get batch_id → poll). It is incomplete on how to retrieve results with the sibling status tool, what a completed batch payload looks like, and any webhook/export caveats beyond what the schema already says.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 8 top-level parameters and the deeply nested per-URL options. The description adds only that per-URL mode, formats, and extraction_schema are honored independently, which is marginally useful but largely restates the schema structure. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Start an asynchronous batch job for a large URL set') plus a scope cap (up to 100 per call) and the return shape (batch_id). It does not, however, distinguish itself from the sibling alterlab_batch_scrape, which sounds functionally identical, so the agent cannot disambiguate from the description alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an explicit trigger condition — use when a normal fetch returns 403/429, a bot-protection page, a CAPTCHA, or an empty JS shell — which is real usage guidance. But it never names an alternative tool, gives no when-not conditions, and offers no routing between this tool, alterlab_batch_scrape, and alterlab_batch_status.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.