An MCP server that gives Claude web scraping powers
The server has 21 tools with descriptions present for most, but exhibits significant quality gaps. The three detailed tools (find_places, find_places_nearby, fetch_page) have strong, context-rich descriptions (150-250 chars each), explaining WHAT, WHEN, and HOW. However, 12 tools (extract_emails, extract_phones, extract_links, extract_social_links, extract_products, extract_by_selector, discover_sitemap_urls, crawl_by_links, detect_platform, fetch_shopify_collections, fetch_shopify_products, fetch_shopify_variants) have minimal descriptions under 50 characters, far below the 72-char minimum baseline for parameter annotations. Input schemas are visible for the three detailed tools with proper type definitions and descriptions for all parameters (find_places: 3 params with types and descriptions; find_places_nearby: 5 params; fetch_page: 7 params). However, 15 tools show NO visible input schema in the provided source, only function signatures. Error handling is present (try/except in find_places and find_places_nearby returning JSON with 'error' and empty results), but error messages lack recovery guidance. Parameter naming follows verb_noun convention (find_places, fetch_page), which is good. However, sensitive tools like make_request lack any permission gates or security annotations. Output structure is returned as JSON strings with query/error/count/results fields for the detailed tools, but 15 other tools have no documented output schemas. The rubric baseline is 4 params/tool average (p10=1, p90=8); the detailed tools (3-7 params) fall within range, but schema quality for the majority is invisible.
Crawl a site by following links
Delete a saved result table
Detect the platform or CMS of a website
Discover page URLs from a site's sitemap
Extract arbitrary fields from a web page using CSS selectors
Extract email addresses from a web page
Extract hyperlinks from a web page
15 of 21 tools lack visible input schemas in source code. This blocks LLM understanding of valid parameters.
12 tools have descriptions under 50 characters: extract_emails, extract_phones, extract_links, extract_social_links, extract_products, discover_sitemap_urls, crawl_by_links, detect_platform, fetch_pages, screenshot_page, list_tables, delete_table. Descriptions provide no context for tool selection or prerequisites.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 37 | <=2025-11-25 | v2 |
Extract phone numbers from a web page
Extract structured product data from a web page
Extract social media links from a web page
Fetch one web page and return its content as clean markdown with metadata. Set js_render=true for pages that need JavaScript to render (SPAs, infinite-scroll listings, most modern storefronts). If a rendered page still comes back sparse, give it longer with wait_ms, or wait for a specific element with wait_for (a CSS selector) — that is more reliable than a fixed delay. Article-shaped pages have their navigation, cookie banners and footers stripped automatically; set main_content=false to keep the whole page. PDFs are extracted to text. `actions` drives the page before reading it (implies js_render). Each is {action, selector, ...}: click, type (text), press (key), wait (ms), wait_for, scroll (times), scroll_to_bottom (max_rounds) for infinite scroll, and click_until_gone (max_clicks) for a 'load more' button. Use it for cookie gates, paginated listings and search forms.
Fetch many web pages in parallel
Fetch collections from a Shopify store
Fetch products from a Shopify store
Fetch product variants from a Shopify store
Search for places and local businesses by name or description — 'the British Museum', 'cafes in Shoreditch'. Returns name, address, coordinates, phone, website, opening hours and category. Data comes from OpenStreetMap, so there are no star ratings or review counts; for those you would need a paid Google Places key. Pass save_as='<table_name>' to store the results.
Find every business of a category within a radius of a place — 'dentists near Bath', 'cafes within 2km of Shoreditch'. This is the tool for local lead generation: it returns name, address, phone, website and opening hours for each. `category` accepts friendly names (cafe, dentist, hotel, solicitor, gym, hairdresser, ...) or a raw OpenStreetMap tag like 'amenity=dentist'. Data is OpenStreetMap, so there are no star ratings. Pass save_as='<table_name>' to store the results.
List saved result tables
Make custom HTTP requests
Query a saved result table with SQL
Take a screenshot of a web page
delete_table is a destructive tool with no confirmation mechanism, permission gate, or error classification. Agents can delete result tables without safeguards. Per pattern:confirmation-request, irreversible operations should support dry-run or confirmation.
make_request accepts arbitrary HTTP calls with no visible schema or input validation. LLM could pass malicious payloads or secrets as parameters. Per pattern:secret-injection, credentials must never be tool parameters; per pattern:tool-gateway, all input must be sanitized.
Output schemas are documented only for find_places, find_places_nearby, and fetch_page. 18 other tools have no visible output schema declaration. LLMs cannot plan downstream tool calls or extract required fields.
fetch_page has 7 parameters (js_render, wait_ms, wait_for, main_content, actions, as_html, plus implicit url) but 'actions' parameter is described as 'List of actions...' without specifying the action object schema (required fields, enum of valid actions: click, type, press, wait, wait_for, scroll, scroll_to_bottom, click_until_gone). LLM cannot construct valid action objects. Per pattern:constrained-input, enums must be explicit.
No tool annotations visible (readOnlyHint, destructiveHint, idempotentHint). Per current MCP spec (2026-07-28), tool annotations are a CURRENT pattern for marking tool safety properties. Only delete_table should be marked destructive; all others are read-only. Missing annotations reduce agent planning safety.
Error handling in find_places and find_places_nearby returns JSON with 'error' field but provides no recovery guidance. Per pattern:recovery-guide, errors must tell LLM what to do next. Generic PlacesError exceptions are caught but not classified as retryable or user-fixable.