{
  "markdown": "# fetchmcp\n\n**A drop-in replacement for the official `fetch` MCP that actually works on modern web pages.**\n\n[![npm](https://img.shields.io/npm/v/@labtoolsstudio/fetchmcp?color=cb3837&logo=npm)](https://www.npmjs.com/package/@labtoolsstudio/fetchmcp)\n[![node](https://img.shields.io/node/v/@labtoolsstudio/fetchmcp?color=3fb950&logo=node.js)](https://nodejs.org)\n[![license](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)\n[![PRs welcome](https://img.shields.io/badge/PRs-welcome-3fb950)](#development--testing)\n\nThe official `fetch` MCP is broken on JavaScript-heavy pages, truncates output at 5,000 characters, and ships an unpatched SSRF vulnerability. `fetchmcp` returns clean, LLM-ready Markdown from any URL — rendering JavaScript when needed, passing basic bot protection without paid proxies, and telling you honestly when a page is blocked instead of hallucinating content. `npx` and go.\n\n![Before and after: the official fetch MCP returns an empty SPA shell, fetchmcp returns clean Markdown](./assets/before-after.png)\n\n```jsonc\n// Replace the official fetch server with this — one line in your MCP config:\n\"fetchmcp\": { \"command\": \"npx\", \"args\": [\"-y\", \"@labtoolsstudio/fetchmcp\"] }\n```\n\n[![Add to Cursor](https://img.shields.io/badge/Add%20to-Cursor-000?logo=cursor)](cursor://anysphere.cursor-deeplink/mcp/install?name=fetchmcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBsYWJ0b29sc3N0dWRpby9mZXRjaG1jcCJdfQ==)\n&nbsp;\n[![Install in VS Code](https://img.shields.io/badge/Install-VS%20Code-007ACC?logo=visualstudiocode)](https://insiders.vscode.dev/redirect/mcp/install?name=fetchmcp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40labtoolsstudio%2Ffetchmcp%22%5D%7D)\n\n## Why switch\n\n| | official `fetch` | `fetchmcp` |\n|---|---|---|\n| JavaScript pages | ❌ empty / broken | ✅ auto-renders in a real browser |\n| Output length | ✂️ truncated at 5,000 chars | ✅ full page, with paging |\n| Bot protection (403 / Cloudflare) | ❌ fails silently | ✅ passes mid-tier walls, no paid proxy |\n| Blocked page | ❌ returns the CAPTCHA as \"content\" | ✅ honest typed error, never fakes it |\n| SSRF safety | ❌ [CVE-2025-65513](https://www.cve.org/) (CVSS 9.3) | ✅ private/metadata IPs refused by default |\n| Cost | free | free, self-hosted, `$0` |\n\n## Install\n\nAdd to your MCP client config (`claude_desktop_config.json`, Cursor `mcp.json`, Cline, etc.):\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"fetchmcp\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@labtoolsstudio/fetchmcp\"]\n    }\n  }\n}\n```\n\n**The install is light** — no browser is downloaded up front, and static reading (fetch → Readability → Markdown) works immediately. The first time a page actually needs JavaScript, `fetchmcp` downloads a stealth Chromium once (~150 MB) automatically, then renders it — still zero-config. To pre-download it at install time, set `FETCHMCP_PREINSTALL_BROWSER=1`. To stay static-only and never download it, set `FETCHMCP_SKIP_BROWSER_DOWNLOAD=1` (JS pages then return an honest `needs_js`).\n\n## Tools\n\n### `read_url`\nFetch any web page as clean Markdown.\n\n| arg | type | description |\n|---|---|---|\n| `url` | string | the URL to fetch (http/https) |\n| `render` | boolean | JS rendering: `true` = always, `false` = never, omitted = automatic (only for empty SPA shells) |\n| `raw` | boolean | return raw HTML instead of Markdown |\n| `headers` | object | extra request headers, e.g. `{\"Authorization\": \"Bearer …\", \"Cookie\": \"…\"}` |\n| `max_length` | integer | cap characters returned (`0` = unlimited, the default) |\n| `start_index` | integer | offset for paging through a long page |\n\n### `read_docs`\nSame engine, tuned for documentation: strips navigation sidebars, headers, and footers so API docs and guides come back as clean reference text. Takes `url`, `render`, `headers`, `max_length`, `start_index`.\n\n## Honest statuses\n\n`fetchmcp` never returns a bot wall, an error page, or a truncated shell dressed up as real content. When it can't read a page it says why, with a typed status: `blocked` (bot protection, with the vendor), `blocked_ssrf`, `needs_js`, `http_error`, `timeout`, `network_error`, `unsupported_content`, or `empty`.\n\n## Configuration (env vars)\n\n| var | default | meaning |\n|---|---|---|\n| `FETCHMCP_TIMEOUT_MS` | `30000` | per-request timeout |\n| `FETCHMCP_MAX_RETRIES` | `2` | retries on network errors / `429` / `503` (with backoff + `Retry-After`) |\n| `FETCHMCP_ALLOW_PRIVATE_IP` | unset | set to `1` to allow private/localhost IPs (trusted intranet docs) |\n| `FETCHMCP_FLARESOLVERR_URL` | unset | self-hosted [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr) endpoint for tougher challenges |\n| `FETCHMCP_SKIP_BROWSER_DOWNLOAD` | unset | set to `1` for static-only: never download Chromium; JS pages return `needs_js` |\n| `FETCHMCP_PREINSTALL_BROWSER` | unset | set to `1` to download Chromium at install time instead of on first JS use |\n\n## Development & testing\n\n```bash\nnpm install          # installs deps (Chromium downloads on first JS use)\nnpm run build        # compile TypeScript to dist/\nnpm test             # unit tests (block detection, SSRF) — no network\nnpm run test:e2e     # live end-to-end suite against real sites\n\n# Poke at any tool/URL by hand — no need to write a script:\nnode test/probe.mjs read_url  https://example.com\nnode test/probe.mjs read_url  https://some-spa.example.com --render\nnode test/probe.mjs read_docs https://docs.python.org/3/library/json.html\nnode test/probe.mjs read_url  https://api.example.com --header \"Authorization=Bearer x\" --max-length 500\nnode test/probe.mjs read_url  https://example.com --full     # print the whole response\n```\n\n`test/probe.mjs --help` semantics are documented at the top of that file.\n\n## How it works\n\nThree tiers, escalating only as needed:\n1. **Static** — plain fetch → [Readability](https://github.com/mozilla/readability) → Markdown. Fast path for most pages.\n2. **Browser** — lazy [patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright) (stealth Chromium) when the static HTML is an empty SPA shell, a bot wall, or a `403/429/503`.\n3. **FlareSolverr** (optional) — only if you've configured an endpoint, for challenges the browser can't clear.\n\n## Star history\n\nIf `fetchmcp` saved you from one more `fetch`-returns-nothing moment, a star helps others find it.\n\n[![Star History Chart](https://api.star-history.com/svg?repos=labtoolsstudio/fetchmcp&type=Date)](https://star-history.com/#labtoolsstudio/fetchmcp&Date)\n\n## License\n\nMIT — see [LICENSE](./LICENSE).\n\n",
  "bytes": 6514,
  "sha": "6c270b6ff383fd65b44f8ac207538323e7909fb7cb4871fdc2b35b785f580483",
  "repo_slug": "labtoolsstudio/fetchmcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_labtools_studio_fetchmcp_ba234e3a/readme"
}