MCP server for RAG and web crawling with Crawl4AI. Provides tools to crawl websites using Crawl4AI, automatically detecting the appropriate crawl method based on URL type (sitemap, txt file, or regular webpage).
This server has three tools with reasonable descriptions but significant gaps in parameter documentation, schema completeness, and error handling. Tool names follow action-verb convention (crawl_, smart_crawl_, rag_query), which is positive. However, parameter descriptions are minimal or missing, input schemas lack proper type constraints, and output schemas are not documented. The code snippet shows FastAPI/pydantic implementation but does not expose explicit MCP tool registration or schema definitions in the source provided. Error handling guidance is absent, no recovery hints, retryability classification, or input validation error messages are visible.
Crawl a single web page and store its content in Supabase. This tool is ideal for quickly retrieving content from a specific URL without following links. The content is stored in Supabase for later retrieval and querying.
Search for relevant content in the crawled pages database using vector similarity search. This tool searches through all previously crawled and stored content using semantic similarity, returning the most relevant chunks based on your query. Results can be filtered by source domain.
Intelligently crawl a URL based on its type and store content in Supabase. This tool automatically detects the URL type and applies the appropriate crawling method: - For sitemaps: Extracts and crawls all URLs in parallel - For text files (llms.txt): Directly retrieves the content - For regular webpages: Recursively crawls internal links up to the specified depth All crawled content is chunked and stored in Supabase for later retrieval and querying.
Input parameters lack detailed descriptions and constraint documentation. For example, 'max_depth' (int), 'max_concurrent' (int), and 'chunk_size' (int) have only minimal descriptions like 'Maximum recursion depth for regular URLs (default: 3)' but do not state valid ranges (e.g., 1-10?), what happens if a negative value is passed, or whether the default is always applied if omitted.
Output schemas are not documented anywhere in the source code. Tool descriptions state what is returned (e.g., 'content is stored in Supabase') but do not specify the response structure, field names, types, or whether pagination is supported. LLMs cannot predict the shape of returned data to plan downstream tool calls.
No error handling guidance. Tool descriptions do not indicate what errors can occur, how to recover from failures, or whether operations are retryable. For example, if a URL is unreachable or Supabase write fails, the agent has no guidance on what to do next.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 54 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 22 | - | v1 |
Numeric parameters (max_depth, max_concurrent, chunk_size, match_count) lack minimum and maximum bounds in descriptions. Unbounded integers allow LLMs to pass absurd values (e.g., max_depth=1000, match_count=999999) that could cause API failures or timeouts.
No idempotency guarantees documented. The crawl_single_page and smart_crawl_url tools modify state (write to Supabase). If an agent retries on failure, is content duplicated, or does the tool detect and skip already-crawled URLs? Without idempotency guarantees, agents risk duplicate records or data corruption on retry.
The 'source' parameter in rag_query is described as 'Optional source domain to filter results' but does not explain the expected format (full URL, domain name, regex pattern?), how it maps to stored metadata, or whether it is case-sensitive.
Input parameter 'url' for crawl_single_page and smart_crawl_url has no format validation rules documented. What schemes are supported (http, https, file://)? Are relative URLs allowed? What is the maximum URL length? This forces LLMs to guess and causes silent failures on invalid input.
rag_query does not document pagination or result limiting behavior. If a query matches thousands of documents, does it return all of them, or cap at match_count? Is there a next_cursor or offset for fetching more results? Context window exhaustion and hallucination risk increase with large unstructured result sets.