Website Scraper MCP Server
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., "@Website Scraper MCP Serverscrape and index https://example.com into AI Search"
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.
Website Scraper MCP Server
A production-ready MCP (Model Context Protocol) server that allows any MCP-compatible AI agent to scrape websites, crawl internal pages, clean content, chunk it, and index everything into Azure AI Search — all through a clean, typed tool interface.
Table of Contents
Related MCP server: Crawl4AI RAG MCP Server
Architecture
website_scraper_mcp/
├── app.py ← Entry point (stdio / SSE transport)
├── server.py ← MCP server + tool dispatcher
├── config.py ← Pydantic Settings (env vars)
├── models.py ← Input/Output Pydantic models
└── tools/
├── scrape.py ← Tool 1 – static/dynamic detection + scraping
├── crawl.py ← Tool 2 – BFS crawler, robots.txt aware
├── clean.py ← Tool 3 – Trafilatura + BS4 content cleaning
├── chunk.py ← Tool 4 – sliding window chunking
└── azure_ai_search.py ← Tools 5 & 7 – index + searchTools
# | Tool | Description |
1 |
| Detect static/dynamic, scrape title/content/links |
2 |
| BFS crawl with depth limit + robots.txt |
3 |
| Strip noise HTML, return readable text |
4 |
| Sliding window chunks (~1 000 chars, 200 overlap) |
5 |
| Upload chunks to Azure AI Search |
6 |
| End-to-end pipeline: crawl → clean → chunk → index |
7 |
| Full-text search on the Azure AI Search index |
Installation
Prerequisites
Python 3.11+
Azure AI Search service (free tier works for testing)
Steps
# 1. Clone the repo
git clone https://github.com/your-org/website-scraper-mcp.git
cd website-scraper-mcp
# 2. Create and activate a virtual environment
python -m venv .venv
# Windows
.venv\Scripts\activate
# Linux/Mac
source .venv/bin/activate
# 3. Install dependencies
pip install -r requirements.txt
# 4. Install Playwright browsers (Chromium)
playwright install chromium
# 5. Copy and fill environment variables
cp .env.example .env
# Edit .env with your Azure credentialsRunning Locally
stdio mode (default — for MCP clients / AI agents)
python -m website_scraper_mcp.app
# or
python -m website_scraper_mcp.app --transport stdioSSE mode (HTTP endpoint for browser-based / HTTP clients)
python -m website_scraper_mcp.app --transport sse --port 8000
# Server available at http://localhost:8000/sseRunning with Docker
# Build and start in SSE mode
docker compose up --build
# Stop
docker compose downThe container exposes port 8000 for SSE transport.
Environment Variables
Variable | Default | Description |
| (required) | Azure AI Search service URL |
| (required) | Admin API key |
|
| Target index name |
|
| Playwright page load timeout (ms) |
|
| Run Chromium headless |
|
| Maximum crawl depth |
|
| Hard cap on pages per crawl |
|
| Polite delay between requests |
|
| Characters per chunk |
|
| Overlap between consecutive chunks |
|
| Python logging level |
Sample MCP Client
Run the included example after starting the server in SSE mode:
python examples/mcp_client_example.pyOr configure it in your MCP-compatible agent (e.g. Claude Desktop mcp_config.json):
{
"mcpServers": {
"website-scraper": {
"command": "python",
"args": ["-m", "website_scraper_mcp.app", "--transport", "stdio"],
"cwd": "/path/to/website-scraper-mcp",
"env": {
"AZURE_SEARCH_ENDPOINT": "https://your-service.search.windows.net",
"AZURE_SEARCH_KEY": "your-key",
"AZURE_SEARCH_INDEX_NAME": "website-content"
}
}
}
}Example API Requests
Via MCP client (Python SDK)
import asyncio
from mcp import ClientSession
from mcp.client.sse import sse_client
async def demo():
async with sse_client("http://localhost:8000/sse") as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# Scrape a single page
result = await session.call_tool("scrape_website", {"url": "https://example.com"})
print(result)
# Full pipeline
result = await session.call_tool("index_website", {
"url": "https://example.com",
"max_depth": 2
})
print(result)
# Search
result = await session.call_tool("search_index", {
"query": "What services does the company provide?",
"top": 5
})
print(result)
asyncio.run(demo())Tool input/output examples
scrape_website
// Input
{"url": "https://example.com"}
// Output
{
"title": "Example Domain",
"url": "https://example.com",
"content": "This domain is for use in illustrative examples...",
"links": ["https://www.iana.org/domains/example"],
"is_dynamic": false,
"metadata": {"description": "..."}
}index_website
// Input
{"url": "https://example.com", "max_depth": 2}
// Output
{
"url": "https://example.com",
"pages_crawled": 4,
"total_chunks": 38,
"indexed_documents": 38,
"failed_documents": 0,
"status": "success",
"errors": []
}search_index
// Input
{"query": "What services does the company provide?", "top": 5}
// Output
{
"query": "What services does the company provide?",
"total_results": 3,
"hits": [
{
"id": "abc123",
"url": "https://example.com/services",
"title": "Our Services",
"content": "We provide cloud, AI, and data services...",
"chunk_number": 0,
"score": 9.8
}
]
}Error Handling
The server handles all errors gracefully and returns structured JSON error responses:
{
"error": "HTTP 404 when fetching https://example.com/missing",
"tool": "scrape_website"
}Handled errors include: invalid URLs, HTTP 4xx/5xx, timeouts, Playwright failures, Azure Search quota errors, network issues, and duplicate document IDs.
License
MIT
Available Tools
5 toolschunk_contentA
Split clean text into overlapping chunks (~1 000 characters each, 200-character overlap). Each chunk has a unique deterministic ID derived from the URL and position. Useful for preparing text for vector embedding or search indexing.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | Source URL to embed in each chunk. | |
| text | Yes | Clean plain text to split. | |
| title | No | Page title to embed in each chunk. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses key behavioral traits: overlapping chunks, deterministic IDs from URL and position. No annotations are provided, so the description carries the full burden. It does not mention edge cases or side effects, but for a text transformation tool, the behavior is sufficiently transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and front-loaded, with three sentences that each serve a purpose: stating the action, detailing the chunk characteristics, and suggesting use cases. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity, the description covers all necessary information: what it does, how it operates (overlap, chunk size, ID generation), and its intended use. No output schema exists, but the behavior is clear enough.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds value beyond the schema by explaining how parameters are used: overlapping mechanics, deterministic ID derivation from URL, and the general split strategy, which enriches the meaning of the parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Split clean text into overlapping chunks'), specifies chunk size (~1000 characters) and overlap (200 characters), and distinguishes from sibling tools (cleaning, crawling, scraping) by focusing on the chunking process.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description mentions use cases ('preparing text for vector embedding or search indexing'), providing clear context. However, it does not explicitly state when not to use the tool or compare to alternatives, though the sibling tool names imply distinct purposes.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
clean_contentA
Clean raw HTML by removing scripts, styles, navigation bars, footers, cookie banners, ads, and other noise. Returns readable plain text keeping only main article content, headings, paragraphs, tables, and lists.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | Optional source URL (helps with relative link resolution). | |
| html | Yes | Raw HTML string to clean. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It explains the transformation (removing noise, keeping text) and return type (readable plain text). However, it does not mention edge cases like malformed HTML, performance, idempotency, or whether the input is mutated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, front-loaded with the action 'Clean raw HTML'. Every sentence serves a purpose: specifying what is removed, what is kept, and the return type. No fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description adequately explains the return value (plain text with structure). It covers both parameters and the core behavior. Missing details on error handling or potential performance implications, but overall sufficient for the tool's simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description does not add new meaning beyond the schema: 'url' is for relative link resolution (as schema notes), 'html' is the input. No parameter-specific elaboration in the description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Clean raw HTML' by removing specific elements (scripts, styles, navigation, etc.) and keeping meaningful content (headings, paragraphs, tables, lists). It distinguishes itself from siblings like scrape_website or chunk_content by focusing on cleaning/transforming HTML to plain text.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies use after scraping HTML, but it does not explicitly state when to use versus alternatives like chunk_content (which splits text) or when not to use (e.g., if HTML is already clean). No exclusions or specific context cues are provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crawl_websiteA
BFS-crawl an entire website starting from the given root URL. Only follows internal (same-domain) links. Respects robots.txt. Avoids duplicate URLs. Limits crawl depth and total page count. Returns every scraped page with title, content, and links.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Root URL to start crawling from. | |
| max_depth | No | How many link-hops deep to crawl (default 2). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, description fully discloses crawl behavior: BFS algorithm, internal links only, respects robots.txt, avoids duplicates, limits depth and page count. Also states returned data (title, content, links). Lacks details on rate limiting or performance impact but is still thorough.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Extremely concise: two sentences covering purpose, behavior, constraints, and output. No redundancy or filler. Information-dense and efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description adequately explains return values (title, content, links). Covers all input parameters, behavior, constraints, and output format. No missing critical information for a crawl tool with two params.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and both parameters are well-described in the schema. The description adds minimal extra context (e.g., 'link-hops' for max_depth) but does not enhance understanding beyond schema defaults and bounds.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states the tool's purpose: BFS-crawl an entire website from a root URL. It specifies algorithm, constraints (internal links, robots.txt, duplicate avoidance, depth/count limits), and output (title, content, links). This distinguishes it from sibling tools like 'scrape_website' (presumably single-page) and 'scrape_full_site'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied: use for full-site crawling. However, no explicit guidance on when to use this tool versus alternatives like 'scrape_website' or 'scrape_full_site'. No when-not-to-use or prerequisite info provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scrape_full_siteA
End-to-end pipeline: crawl every internal page of a website, clean the HTML of each page, and optionally split into chunks. Returns a structured result with every page's title, clean content, links, metadata, and (if requested) text chunks. Handles both static and dynamic pages automatically.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Root website URL to start from. | |
| chunk | No | Whether to split page content into chunks. | |
| clean | No | Whether to clean HTML before returning content. | |
| max_depth | No | Maximum crawl depth (default 2). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It details the pipeline steps (crawl, clean, optionally chunk) and the return structure (title, content, links, metadata, chunks). It also mentions handling both static and dynamic pages, adding valuable context. However, it does not address resource consumption, rate limits, or authentication.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences: first describes the pipeline, second defines the return. No wasted words and front-loaded with the key action.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity of crawling and cleaning, the description covers the main outputs and mentions dynamic page handling. It lacks details on the cleaning process, max_depth behavior, or prerequisites like authentication, but remains largely complete for selection purposes.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 each parameter. The description does not add additional meaning beyond what the schema provides, placing it at the baseline of 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it's an end-to-end pipeline for crawling every internal page, cleaning HTML, and optionally chunking. It distinguishes from siblings like crawl_website, scrape_website, chunk_content, and clean_content by combining all steps.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains what the tool does and implies use cases for full-site scraping, but does not explicitly state when not to use it or list alternatives such as crawl_website or scrape_website for simpler tasks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scrape_websiteA
Scrape a single web page. Automatically detects whether the page is static (uses httpx + BeautifulSoup) or dynamic/JS-rendered (uses Playwright headless Chromium). Returns the page title, clean content, all internal/external links, and page metadata.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Full URL of the page to scrape (e.g. https://example.com). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses auto-detection of static vs dynamic pages and the return payload. With no annotations, it covers key behaviors but omits error handling, rate limits, or consent requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero redundancy. Front-loaded with purpose, then technical details. Every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a single required parameter and no output schema, the description adequately explains functionality and outputs. Could mention pagination or size limits, but overall sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the description adds no extra meaning to the URL parameter beyond what the schema provides. Baseline score applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Scrape a single web page' and lists specific outputs (title, content, links, metadata). It distinguishes from sibling tools by focusing on a single page, not crawling or content processing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies single-page usage but does not explicitly tell when to use alternatives like crawl_website or scrape_full_site. No exclusion criteria are mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v1.0.0- First observed
chunk_content - First observed
clean_content - First observed
crawl_website - First observed
scrape_full_site - First observed
scrape_website
TDQS
Scored across 5 tools
Each tool has a unique purpose: single-page scrape, full-site crawl, cleaning, chunking, and an end-to-end pipeline. No two tools overlap in functionality.
All tool names follow a consistent verb_noun pattern in snake_case (e.g., scrape_website, clean_content), making them predictable and easy to distinguish.
Five tools is appropriate for a website scraping server: it covers the essential operations without being overly sparse or bloated.
The tool surface covers the full workflow: scraping single pages, crawling entire sites, cleaning HTML, and chunking text. No essential operation is missing for the stated domain.
Maintenance
Related MCP Connectors
- fastCRWOAuthio.github.us
Scrape, crawl, map & search the web. Open-source, self-hostable Rust crawler & search for AI agents.
Clean Markdown and AI-readability scoring for any URL. Built for AI agents.
Web scraping for AI agents. Extract text and metadata from any URL worldwide. $0.005/page.
Cloud scraping & crawling API for AI agents. Turn any URL into clean, LLM-ready markdown.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides AI agents and coding assistants with advanced web crawling and RAG capabilities, allowing them to scrape websites and leverage that knowledge through various retrieval strategies.2MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to crawl websites, extract and store web content with semantic search capabilities using vector embeddings, and retrieve information through natural language queries with tag-based filtering and intelligent content cleaning.-
- AlicenseNot gradedqualityDmaintenanceProvides web crawling and RAG capabilities for AI agents, enabling scraping of websites, storing content in a vector database (Supabase), and performing semantic search over crawled data.MIT
- AlicenseNot gradedqualityDmaintenanceProvides AI agents and assistants with advanced web crawling and RAG capabilities, enabling them to scrape websites and perform semantic search over crawled content.1MIT