scrapy-mcp
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., "@scrapy-mcpScrape the main content of example.com as markdown"
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.
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-mcpOr install it:
uv pip install scrapy-mcp
scrapy-mcpThe 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 one page as |
| Pull structured fields with CSS/XPath selectors. |
| Extract every HTML |
| List de-duplicated links on a page. |
| Read a sitemap (gzip + sitemap-index aware). |
| Is a URL crawlable? Returns the crawl-delay and sitemaps. |
| Start a bounded BFS crawl; returns a |
| State + pages scraped for a crawl. |
| Page through a crawl's scraped items. |
| 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 |
|
| User-Agent header. |
|
| Obey |
|
| Seconds between requests to a host. |
|
| Global concurrency. |
|
| Per-host concurrency. |
|
| Per-request timeout (s). |
|
| Retries on transient failures. |
|
| Adapt delay to server latency. |
|
| Max characters returned per page (then truncated). |
|
| Wall-clock cap for a blocking single fetch (s). |
|
| Crawl page default / hard cap. |
|
| Crawl depth default / hard cap. |
|
| Where crawl jobs are stored. |
|
| Delete crawl jobs older than this (0 disables). |
|
| 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 toolscancel_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_linksA
Fetch a page and return its links (de-duplicated, absolute URLs).
same_domain: keep only links on the same host as url.
pattern: keep only links whose URL matches this regular expression.
limit: maximum number of links to return (1-2000).
Each link is {"url": ..., "text": ..., "nofollow": bool}.
Inputs: url (required), limit, pattern, obey_robots, +1 more.
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 tostart_url's host.selectors: same format as theextracttool; when given, each crawled page yields the extracteddata. 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
Scored across 10 tools
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.
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.
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.
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
Related MCP Connectors
Web scraping MCP server — scrape, extract structured data, screenshot any site with anti-bot bypass.
One MCP server for all web data. Scrape, search, crawl, and AI research in one install.
Web scraping MCP server: any URL to Markdown or JSON, with JavaScript rendering and batch jobs.
One MCP for the Web. Easily search, crawl, navigate, and extract websites without getting blocked.…
Related MCP Servers
- FlicenseBqualityDmaintenanceAn MCP Server for Web scraping and Crawling, built using Crawl4AI224-
- FlicenseBqualityDmaintenanceA 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.2210-
- AlicenseNot gradedqualityBmaintenanceRemote 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.1MIT
- FlicenseAqualityDmaintenanceA 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.41-