Render Fetch MCP
Handles Cloudflare Markdown-for-Agents sites and bot challenge interstitials, with Web Bot Auth registration plumbing for Cloudflare's bot directory.
The MCP server is named 'Render Fetch MCP' and is designed as a self-hosted remote server for retrieving bot-unfriendly page content as Markdown and screenshots.
Deployed as a Replit Autoscale app, using Replit's fronting infrastructure for production hosting.
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., "@Render Fetch MCPfetch this article as markdown: https://example.com/blog/post"
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.
Render Fetch MCP
MCP server for retrieving bot-unfriendly page content.
A self-hosted remote MCP server that returns the readable content of a URL as Markdown — and, on request, a screenshot — escalating to headless Chromium only when cheaper methods fail. Connects to claude.ai as a custom connector.
Built for one operator, low request frequency, latency-tolerant. Correctness and clarity of failure beat speed everywhere.
Upstream: sidney/web-to-markdown-mcp
(MIT), vendored at a pinned SHA — see DECISIONS.md.
Tools
fetch_url_as_markdown
Escalates through four tiers, using the cheapest that produces usable content:
Tier | Mechanism | Typical cost | Handles |
1 | Plain HTTP GET with | ~300 ms | Cloudflare Markdown-for-Agents sites, anything doing content negotiation |
2 | Plain HTTP GET + trafilatura | ~500 ms | Ordinary static HTML and server-rendered pages |
2.5 |
| ~700 ms | Sites blocking on TLS/JA3 fingerprint alone |
3 | patchright (anti-detection Playwright fork) + Chromium | 2–8 s | JS-rendered SPAs, soft bot walls, JS-shell pages |
Tier 3 is the rare path. It exists so that the rare page is readable at all, not so that it is readable quickly.
Returns a structured envelope:
{
"content": "<markdown>",
"tier_used": 1,
"identity_mode": "stealth",
"final_url": "https://example.com/",
"http_status": 200,
"content_ok": true,
"truncated": false,
"next_offset": null,
"hint": null
}content_ok is the load-bearing field: false when the extraction looks
like a bot-challenge interstitial, a JS shell, a login wall, or is
implausibly short. When it is false, hint names the next thing to try — for
a wall, that is the Wayback Machine connector, so the calling model stops
retrying something that will not start working.
capture_page
Screenshots the rendered page as vision-ready image tiles. Always tier 3.
One tall full-page PNG is close to useless to a vision model: it gets resized until the body text is a few pixels tall, costs a full image's tokens, and conveys nothing. So the page is tiled at a size computed from the model's published token and pixel limits such that no resize happens at all. Blank and near-blank regions are detected by entropy and ink ratio and skipped, with the dropped vertical ranges stated in the response.
Modes: viewport (1 tile, the cheap default), full (tiled), element
(single CSS-selected clip).
Cost: ~1334 visual tokens per tile. Four tiles ≈ 5 336; eight ≈ 10 672.
Related MCP server: @hauntapi/mcp-server
Limits
No authenticated or logged-in pages. Clean context, no cookies.
Interactive Cloudflare Turnstile, DataDome, PerimeterX and Kasada are not bypassed. Datacenter egress makes encountering them more likely, not less.
Slow progressive-render SPAs may return partial content at budget expiry.
These are readers, not automation tools. They cannot click, fill, or log in.
capture_pageis expensive in tokens. Usefetch_url_as_markdownfor anything fundamentally textual.
Endpoints
Route | Purpose |
| The MCP endpoint (streamable HTTP, stateless) |
|
|
| Web Bot Auth key |
Auth is a secret path segment compared in constant time. A mismatch returns 404, not 403 — a 403 confirms the path space exists.
Use /status in production. Replit's fronting infrastructure intercepts
the exact path /healthz on a published Autoscale app and answers with its
own branded 404 that never reaches this process, so a /healthz 404 in
production says nothing about the app's health. All three names work locally.
Configuration
Secret | Default | Purpose |
| none — required | Secret path segment |
|
|
|
| generated | Ed25519 private key for Web Bot Auth |
| none | Public origin, for signing and own-origin SSRF checks |
|
| Truncation cap |
|
| Tier 3 stabilisation budget |
|
| Hard wall-clock cap |
|
| Idle browser reaper |
|
| Screenshot tile cap (hard max 8) |
|
|
Identity
stealth (default) presents a realistic browser identity: current Chrome UA,
browser header ordering, and curl_cffi TLS impersonation at tier 2.5.
declared self-identifies honestly and signs requests with Web Bot Auth —
Ed25519, HTTP Message Signatures (RFC 9421), and a Signature-Agent header
pointing at the directory this server publishes. Registering with Cloudflare's
bot directory is a later manual step; the plumbing is already here, so
registering is a form submission rather than a rebuild.
robots.txt is not consulted in either mode. This server acts for one
identified human making individual requests, not as a crawler. See
DECISIONS.md for the recorded reasoning and its tension with
declared mode.
Local development
python -m venv .venv && .venv/bin/pip install -r requirements-dev.txt
.venv/bin/patchright install chromium
export MCP_PATH_TOKEN=$(python -c "import secrets;print(secrets.token_urlsafe(32))")
.venv/bin/python main.py # http://localhost:5000
.venv/bin/python -m pytest tests/ # 91 testsDeployment
Replit Autoscale, 2 vCPU / 4 GiB, max 1 instance.
build : pip install -r requirements.txt && patchright install chromium && python scripts/verify_build.py
run : python main.pyChromium is installed at build time (~300 MB, baked into the image) and launched at request time (~2 s, lazily, on the first tier-3 call). Conflating the two is the main way this deployment goes wrong: installing at runtime on a scale-to-zero container means a 300 MB download on every cold start, inside a request timeout.
See WORK-ORDER.md for the console steps, and AGENTS.md for the upstream update policy.
This server cannot be deployed
Maintenance
Related MCP Connectors
Screenshot, PDF, OG-image, and page extraction (markdown/JSON) over MCP. Bearer key or x402.
MCP server for web extraction and rendering via AceDataCloud WebExtrator
Document-to-Markdown MCP server — convert PDF, Office and HTML into LLM-ready Markdown.
MCP server (stdio): fetch web pages as clean readable markdown via the AgentForge API
Related MCP Servers
- FlicenseNot gradedqualityNot gradedmaintenanceAn MCP server for web content extraction that converts HTML pages into clean, LLM-optimized Markdown using Mozilla's Readability. It supports batch processing, intelligent multi-page crawling, and configurable caching while respecting robots.txt standards.33 npm-
- AlicenseAqualityBmaintenanceWeb extraction MCP server for AI agents. Extract structured data from any URL with built-in Cloudflare bypass, JavaScript rendering, and intelligent parsing. Returns clean markdown or JSON.5794 npm2MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server for intelligent web content extraction from JavaScript-heavy sites using single-file and trafilatura. It enables AI agents to fetch, render, and paginate through clean article content and metadata.20MIT
- AlicenseNot gradedqualityCmaintenanceMCP server for retrieving web pages as clean Markdown, with configurable detail levels and optional Chromium rendering for JavaScript-heavy pages.1MIT