Skip to main content
Glama
scrapy-mcp
by eitan3

scrapy-mcp

A headless web-scraping MCP server built on Scrapy. It exposes Scrapy's scraping primitives — polite fetching, CSS/XPath extraction, link and table extraction, sitemap and robots.txt reading, and bounded asynchronous crawls — as MCP tools an agent can call over stdio.

  • Headless, no rendering. Pages are fetched and parsed as HTML; no browser, no JavaScript execution. This keeps the footprint tiny — it runs comfortably on weak machines.

  • Reactor-safe. Every operation runs in a short-lived Scrapy subprocess, so Twisted's reactor never lives inside the asyncio MCP server (no ReactorNotRestartable), and memory is reclaimed after each call.

  • Polite by default. Obeys robots.txt, throttles with AutoThrottle, and enforces hard page/depth caps so a crawl can't run away.

Install / run

Run straight from PyPI with uv — no install step:

uvx scrapy-mcp

Or install it:

uv pip install scrapy-mcp
scrapy-mcp

The server speaks MCP over stdio. Point any MCP client at it. For Claude Desktop, add to claude_desktop_config.json:

{
  "mcpServers": {
    "scrapy": {
      "command": "uvx",
      "args": ["scrapy-mcp"]
    }
  }
}

Related MCP server: silkworm-mcp

Tools

Tool

What it does

fetch_page(url, format, max_bytes, obey_robots)

Fetch one page as markdown (default), text, or html.

extract(url, selectors, obey_robots)

Pull structured fields with CSS/XPath selectors.

extract_tables(url, max_tables, obey_robots)

Extract every HTML <table> as {headers, rows}.

extract_links(url, same_domain, pattern, limit, obey_robots)

List de-duplicated links on a page.

get_sitemap(url, limit, obey_robots)

Read a sitemap (gzip + sitemap-index aware).

check_robots(url, user_agent)

Is a URL crawlable? Returns the crawl-delay and sitemaps.

start_crawl(start_url, allow_patterns, deny_patterns, max_pages, max_depth, same_domain, selectors, ...)

Start a bounded BFS crawl; returns a job_id.

crawl_status(job_id)

State + pages scraped for a crawl.

crawl_results(job_id, cursor, limit)

Page through a crawl's scraped items.

cancel_crawl(job_id)

Stop a running crawl; keep results so far.

Selector format (extract / start_crawl)

selectors maps an output field to a selector. Each value is either a CSS string (first match) or an object for more control:

{
  "title": "h1::text",
  "price": "span.price::text",
  "all_links": {"css": "a::attr(href)", "all": true},
  "first_heading": {"xpath": "//h1/text()"}
}

"all": true returns every match as a list; otherwise the first match is returned.

Crawls are asynchronous

start_crawl returns immediately with a job_id. The crawl runs as a detached worker that streams results to disk, so it survives a server restart. Poll crawl_status(job_id), then read items with crawl_results(job_id) (safe to call mid-crawl for partial results). Jobs are stored under the system temp dir and reclaimed after 7 days (configurable).

Configuration

All settings are optional environment variables (sensible, polite defaults tuned for a weak host). They're how you tune a uvx scrapy-mcp deployment.

Variable

Default

Meaning

SCRAPY_MCP_USER_AGENT

scrapy-mcp/<version> …

User-Agent header.

SCRAPY_MCP_OBEY_ROBOTS

true

Obey robots.txt.

SCRAPY_MCP_DOWNLOAD_DELAY

0.5

Seconds between requests to a host.

SCRAPY_MCP_CONCURRENT_REQUESTS

8

Global concurrency.

SCRAPY_MCP_CONCURRENT_REQUESTS_PER_DOMAIN

4

Per-host concurrency.

SCRAPY_MCP_DOWNLOAD_TIMEOUT

30

Per-request timeout (s).

SCRAPY_MCP_RETRY_TIMES

2

Retries on transient failures.

SCRAPY_MCP_AUTOTHROTTLE

true

Adapt delay to server latency.

SCRAPY_MCP_MAX_BYTES

50000

Max characters returned per page (then truncated).

SCRAPY_MCP_REQUEST_TIMEOUT

60

Wall-clock cap for a blocking single fetch (s).

SCRAPY_MCP_DEFAULT_MAX_PAGES / _MAX_PAGES_CAP

50 / 1000

Crawl page default / hard cap.

SCRAPY_MCP_DEFAULT_MAX_DEPTH / _MAX_DEPTH_CAP

2 / 10

Crawl depth default / hard cap.

SCRAPY_MCP_JOB_DIR

<tmp>/scrapy_mcp_jobs

Where crawl jobs are stored.

SCRAPY_MCP_JOB_TTL_DAYS

7

Delete crawl jobs older than this (0 disables).

SCRAPY_MCP_LOG_LEVEL

ERROR

Scrapy log level (to stderr).

Development

uv venv
uv pip install -e ".[dev]"
uv run pytest          # unit tests (no network)
uv build               # build wheel + sdist into dist/

License

MIT © Eitan Hadar

Available Tools

10 tools
cancel_crawlA

Stop a running crawl by killing its worker process. Results so far are kept.

Inputs: job_id (required).

check_robotsA

Check the site's robots.txt: is url crawlable, and what crawl-delay applies?

user_agent: the agent to evaluate rules for (defaults to the server's user agent). Returns {allowed, has_robots, crawl_delay, request_rate, sitemaps, robots_url}. Sites with no robots.txt are reported as allowed (has_robots=false).

Inputs: url (required), user_agent.

crawl_resultsA

Page through a crawl's scraped items.

cursor: line offset to start from (use the returned next_cursor to continue). limit: items per page (1-1000). Safe to call while the crawl is still running -- you get whatever has been written so far.

Inputs: job_id (required), limit, cursor.

crawl_statusA

Report a crawl's state and progress.

state is one of: starting, running, finished, failed, cancelled, interrupted. ('interrupted' means the worker process died without finishing -- e.g. the machine or server restarted; any results gathered so far are still readable.)

Inputs: job_id (required).

extractA

Fetch a page and pull structured fields out of it with CSS or XPath selectors.

selectors maps an output field name to a selector. Each value is either:

  • a CSS string, e.g. "h1::text" or "a.product::attr(href)" (returns the first match), or

  • an object: {"css": "...", "all": true} / {"xpath": "//h1/text()", "all": true} ("all": true returns every match as a list; default returns the first match).

Example: {"title": "h1::text", "prices": {"css": ".price::text", "all": true}} Returns {"data": {field: value | [values]}}.

Inputs: url (required), selectors (required), obey_robots.

extract_tablesA

Fetch a page and extract every HTML as {headers, rows}.

max_tables: cap on how many tables to return (1-100). Each table is {"headers": [...], "rows": [[cell, ...], ...], "n_rows": int, "n_cols": int}.

Inputs: url (required), max_tables, obey_robots.

fetch_pageA

Fetch a single web page and return its content (no JavaScript rendering).

format: 'markdown' (default, compact and readable), 'text' (visible text only), or 'html' (raw HTML). max_bytes: cap on returned characters; defaults to the server's SCRAPY_MCP_MAX_BYTES. Oversized content is truncated and truncated is set to true. obey_robots: override the server's robots.txt policy for this call only.

An HTTP error status (404, 500, ...) is returned in status, not raised.

Inputs: url (required), format, max_bytes, obey_robots.

get_sitemapA

Fetch a sitemap and return the URLs it lists.

Handles gzip-compressed sitemaps and recurses one level of into its child sitemaps. url should point at a sitemap (e.g. https://site.com/sitemap.xml). limit: maximum URLs to return (1-50000). Each entry is {"loc": ..., "lastmod": ..., "changefreq": ..., "priority": ...}.

Inputs: url (required), limit, obey_robots.

start_crawlA

Start a bounded breadth-first crawl. Returns a job_id immediately (non-blocking).

The crawl follows in-scope links from start_url up to max_pages / max_depth.

  • allow_patterns / deny_patterns: regexes a link URL must match / must not match.

  • same_domain (default true): restrict the crawl to start_url's host.

  • selectors: same format as the extract tool; when given, each crawled page yields the extracted data. Otherwise each page yields a short text excerpt.

  • obey_robots, download_delay: per-crawl overrides of the server defaults.

Poll progress with crawl_status(job_id) and read items with crawl_results(job_id).

Inputs: start_url (required), max_depth, max_pages, selectors, +5 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

    TDQS

    A4.2/5.0

    Scored across 10 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose: fetching a page, extracting tables, links, structured data, checking sitemap/robots, and managing crawls. There is no overlap between single-page extraction tools and crawl lifecycle tools.

    Naming Consistency5/5

    Tool names consistently follow a verb_noun pattern: extract_tables, extract_links, fetch_page, get_sitemap, check_robots, start_crawl, crawl_status, etc. The generic 'extract' is slightly less patterned but still readable and predictable.

    Tool Count5/5

    With 10 tools, the server is well-scoped for its purpose. The set balances single-page extraction utilities with essential crawl management operations without unnecessary bloat.

    Completeness4/5

    The domain of web scraping and crawling is well covered: page fetching, link/table/structured extraction, robots and sitemap handling, plus full crawl lifecycle (start, status, results, cancel). Minor gap is lack of a tool to list all crawls, but core workflows are complete.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      B
      quality
      D
      maintenance
      A full-featured MCP server for building scrapers, with tools for page fetching, HTML parsing, CSS/XPath querying, and spider generation using silkworm-rs and scraper-rs.
      22
      10
      -
    • A
      license
      Not graded
      quality
      B
      maintenance
      Remote MCP server for web scraping with anti-bot evasion. Provides stealth HTTP fetching, headless browser with Cloudflare bypass, CSS selectors, YouTube transcripts, and Markdown conversion.
      1
      MIT
    • F
      license
      A
      quality
      D
      maintenance
      A portable MCP server that scrapes SPA/JS-rendered webpages and extracts structured API endpoint data. It uses headless Chromium to render JavaScript and provides tools for scraping, endpoint extraction, screenshots, and database seeding.
      4
      1
      -