Scrapy MCP
Scrapy MCP — Universal Web Crawling & Scraping
A general-purpose MCP (Model Context Protocol) server for crawling and extracting structured data from any website. Inspired by Scrapy's architecture.
Architecture
User (Claude) → MCP Tools → Engine → Scheduler → Downloader → Spider → Pipeline → Result
↓ ↓ ↓
Settings Middleware ExtractorsEngine — Central coordinator (BFS crawl loop)
Scheduler — FIFO queue with URL deduplication
Downloader — Async HTTP via
httpxwith middleware chain (retry, UA rotation, rate limiting)Spider — Parses responses using configurable CSS/XPath/regex extractors
Pipeline — Post-processing chain (clean, validate, transform, dedup)
Middleware — Pluggable hooks for request/response processing
Installation
pip install -r requirements.txtRegister with Claude Code
Edit ~/.claude/mcp.json:
{
"mcpServers": {
"scrapy-mcp": {
"command": "python",
"args": ["d:/project/scrapy-mcp/server.py"]
}
}
}MCP Tools
1. crawl — Structured crawling
Crawl a website and extract structured data using CSS selectors or XPath.
Parameters:
Param | Type | Required | Description |
| string[] | ✅ | Starting URLs |
| string | ❌ | Pre-configured spider name (from spiders/ directory) |
| string | ❌ | CSS/XPath selector for item containers |
| object | ❌ | Field extraction rules |
| object | ❌ | Pagination config |
| integer | ❌ | Max pages to crawl (default: 10) |
| integer | ❌ | Max link depth (default: 2) |
| string | ❌ | json / markdown / csv (default: json) |
| string[] | ❌ | Restrict to domains |
Example:
crawl({
"urls": ["https://books.toscrape.com"],
"item_selector": "article.product_pod",
"fields": {
"title": {"selector": "h3 a", "attr": "title"},
"price": {"selector": ".price_color", "regex": "([\\d.]+)"}
},
"pagination": {"type": "next_link", "selector": ".next a", "max_pages": 3}
})2. scrape_page — Single page extraction
Fetch and extract content from a single page. Supports multiple modes.
Parameters:
Param | Type | Required | Description |
| string | ✅ | Target page URL |
| string | ❌ | auto / markdown / structured / raw (default: auto) |
| boolean | ❌ | Extract Schema.org / Open Graph (default: true) |
| boolean | ❌ | Extract all links (default: false) |
| boolean | ❌ | Extract all images (default: false) |
| object | ❌ | Custom CSS selectors for specific elements |
Modes:
auto — Smart: returns structured JSON if schema data found, otherwise markdown
markdown — Clean readable text with headings, images, links
structured — Full JSON with all extracted metadata + schema data
raw — Original HTML source
3. search_and_crawl — Search then crawl
Search any website and crawl each result page for details.
Parameters:
Param | Type | Required | Description |
| string | ✅ | URL template with |
| string | ✅ | Search keywords |
| string | ❌ | Spider name for result pages |
| string | ❌ | Selector for result items on search page |
| string | ❌ | Selector for links within results |
| object | ❌ | Fields to extract from each result page |
| integer | ❌ | Max results (default: 10) |
| boolean | ❌ | Crawl each result page (default: true) |
4. extract_schema — Structured data extraction
Extract Schema.org JSON-LD, Open Graph, Twitter Cards, and meta tags.
Parameters:
Param | Type | Required | Description |
| string | ❌ | Page URL |
| string | ❌ | Or provide raw HTML |
| string[] | ❌ | Filter by type (e.g. ["Product", "Article"]) |
| boolean | ❌ | Include raw JSON-LD objects |
5. list_spiders — Show available spiders
Lists all pre-configured spider definitions from the spiders/ directory.
Spider Configuration (YAML)
Create YAML files in spiders/ to define reusable spiders without writing code:
name: my-spider
description: "What this spider does"
start_urls:
- "https://example.com/items"
item_selector: ".item"
fields:
title:
selector: ".title"
type: text
link:
selector: "a"
type: attr
attr: href
transform: absolute_url
pagination:
type: next_link
selector: ".next a"
max_pages: 5See spiders/example.yml for an annotated template and spiders/books_toscrape.yml for a working example.
Field config reference
Key | Description |
| CSS or XPath expression |
|
|
| HTML attribute to extract (e.g. |
| Regex to apply after extraction (first group returned) |
|
|
| Fallback value |
Pagination types
Type | Description |
| Follow a "next" link using a CSS selector |
| Generate URLs from a |
| Scroll-based (requires JS renderer — not yet supported) |
Settings
Default settings (overridable via spider config):
Setting | Default | Description |
| 0.5s | Delay between requests to same domain |
| 8 | Max simultaneous requests |
| 30s | Request timeout |
| 3 | Max link depth |
| 50 | Max pages to crawl |
| 500 | Max items to collect |
| 3 | Retry attempts on failure |
| [500, 502, 503, 504, 408, 429] | Codes to retry |
| false | Respect robots.txt |
Supported Extraction
CSS selectors —
.class,#id,div > p,a[href]XPath —
/html/body/div,//article//h2Regex — Post-process extracted text
Schema.org — JSON-LD, microdata
Open Graph — og:title, og:description, og:image, etc.
Meta tags — description, keywords, etc.
Auto-extraction — All links, images, tables from a page
Quick Test
cd d:/project/scrapy-mcp
# Test extraction
python -c "
from mcp_scrapy.extractors import FieldExtractor
import httpx, asyncio
async def test():
async with httpx.AsyncClient() as c:
r = await c.get('https://httpbin.org/html')
ext = FieldExtractor(r.text)
print('Title:', ext.extract_field({'selector': 'h1'}))
print('Links:', len(ext.extract_all_links()))
asyncio.run(test())
"
# Test spider loading
python -c "
from mcp_scrapy.spider import SpiderLoader
loader = SpiderLoader(['spiders'])
for s in loader.list_all():
print(f'{s[\"name\"]}: {s[\"description\"]}')
"Project Structure
scrapy-mcp/
├── server.py # MCP entry point
├── requirements.txt
├── mcp_scrapy/
│ ├── __init__.py
│ ├── engine.py # CrawlEngine coordinator
│ ├── scheduler.py # Request queue + dedup
│ ├── downloader.py # Async HTTP + middleware
│ ├── spider.py # Spider + YAML loader
│ ├── request.py # Request/Response/Item types
│ ├── pipelines.py # Item post-processing
│ ├── middleware.py # Downloader middleware
│ ├── extractors.py # CSS/XPath/regex field extraction
│ ├── exporters.py # JSON/Markdown/CSV output
│ ├── schema_extractor.py # Schema.org / Open Graph
│ ├── settings.py # Configuration
│ └── tools/
│ ├── __init__.py
│ ├── crawl.py # crawl tool
│ ├── scrape_page.py # scrape_page tool
│ ├── search.py # search_and_crawl tool
│ ├── extract_schema.py # extract_schema tool
│ └── list_spiders.py # list_spiders tool
├── spiders/ # Spider YAML configs
│ ├── example.yml
│ ├── hackernews.yml
│ └── books_toscrape.yml
└── tests/
├── test_extractors.py
├── test_pipelines.py
└── test_scheduler.pyLatest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/B1unt-alt/Scrapy-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server