Skip to main content
Glama

fetchmcp

A drop-in replacement for the official fetch MCP that actually works on modern web pages.

npm node license PRs welcome

The 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.

Before and after: the official fetch MCP returns an empty SPA shell, fetchmcp returns clean Markdown

// Replace the official fetch server with this — one line in your MCP config:
"fetchmcp": { "command": "npx", "args": ["-y", "@labtoolsstudio/fetchmcp"] }

Add to Cursor   Install in VS Code

Why switch

official fetch

fetchmcp

JavaScript pages

❌ empty / broken

✅ auto-renders in a real browser

Output length

✂️ truncated at 5,000 chars

✅ full page, with paging

Bot protection (403 / Cloudflare)

❌ fails silently

✅ passes mid-tier walls, no paid proxy

Blocked page

❌ returns the CAPTCHA as "content"

✅ honest typed error, never fakes it

SSRF safety

CVE-2025-65513 (CVSS 9.3)

✅ private/metadata IPs refused by default

Cost

free

free, self-hosted, $0

Related MCP server: WebFetch MCP Server

Install

Add to your MCP client config (claude_desktop_config.json, Cursor mcp.json, Cline, etc.):

{
  "mcpServers": {
    "fetchmcp": {
      "command": "npx",
      "args": ["-y", "@labtoolsstudio/fetchmcp"]
    }
  }
}

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).

Tools

read_url

Fetch any web page as clean Markdown.

arg

type

description

url

string

the URL to fetch (http/https)

render

boolean

JS rendering: true = always, false = never, omitted = automatic (only for empty SPA shells)

raw

boolean

return raw HTML instead of Markdown

headers

object

extra request headers, e.g. {"Authorization": "Bearer …", "Cookie": "…"}

max_length

integer

cap characters returned (0 = unlimited, the default)

start_index

integer

offset for paging through a long page

read_docs

Same 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.

Honest statuses

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.

Configuration (env vars)

var

default

meaning

FETCHMCP_TIMEOUT_MS

30000

per-request timeout

FETCHMCP_MAX_RETRIES

2

retries on network errors / 429 / 503 (with backoff + Retry-After)

FETCHMCP_ALLOW_PRIVATE_IP

unset

set to 1 to allow private/localhost IPs (trusted intranet docs)

FETCHMCP_FLARESOLVERR_URL

unset

self-hosted FlareSolverr endpoint for tougher challenges

FETCHMCP_SKIP_BROWSER_DOWNLOAD

unset

set to 1 for static-only: never download Chromium; JS pages return needs_js

FETCHMCP_PREINSTALL_BROWSER

unset

set to 1 to download Chromium at install time instead of on first JS use

Development & testing

npm install          # installs deps (Chromium downloads on first JS use)
npm run build        # compile TypeScript to dist/
npm test             # unit tests (block detection, SSRF) — no network
npm run test:e2e     # live end-to-end suite against real sites

# Poke at any tool/URL by hand — no need to write a script:
node test/probe.mjs read_url  https://example.com
node test/probe.mjs read_url  https://some-spa.example.com --render
node test/probe.mjs read_docs https://docs.python.org/3/library/json.html
node test/probe.mjs read_url  https://api.example.com --header "Authorization=Bearer x" --max-length 500
node test/probe.mjs read_url  https://example.com --full     # print the whole response

test/probe.mjs --help semantics are documented at the top of that file.

How it works

Three tiers, escalating only as needed:

  1. Static — plain fetch → Readability → Markdown. Fast path for most pages.

  2. Browser — lazy patchright (stealth Chromium) when the static HTML is an empty SPA shell, a bot wall, or a 403/429/503.

  3. FlareSolverr (optional) — only if you've configured an endpoint, for challenges the browser can't clear.

Star history

If fetchmcp saved you from one more fetch-returns-nothing moment, a star helps others find it.

Star History Chart

License

MIT — see LICENSE.

Available Tools

2 tools
read_docsRead Documentation Page as MarkdownA

Fetch a documentation or reference page and return only its main content as clean Markdown, stripping navigation sidebars, headers, footers, and other page chrome. Use this for API docs, guides, and reference pages. For general web pages use read_url. Same JS-rendering, anti-bot, and honest-error behavior as read_url.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesThe documentation URL to fetch (http or https).
renderNoJS rendering: true = always, false = never, default = automatic (only for empty SPA shells).
headersNoExtra HTTP headers, e.g. an Authorization token or Cookie for docs behind a login.
max_lengthNoMaximum characters to return. Default 0 = unlimited.
start_indexNoCharacter offset to start from. Default: 0.

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It mentions 'Same JS-rendering, anti-bot, and honest-error behavior as read_url' and describes content stripping, which gives some behavioral insight. However, it relies on the sibling tool's behavior without explaining what those terms mean in this context, leaving gaps about failure modes or side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences long, front-loaded with the primary purpose, and every sentence adds value. It efficiently covers what, when, and how this tool differs from the sibling without any fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (5 parameters, nested headers object) and absence of an output schema, the description adequately explains the return format ('clean Markdown') and use case. It references shared behavior with read_url, which is acceptable for an agent familiar with that sibling, but could be more self-contained. Overall complete enough for a motivated agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema covers 100% of parameters with detailed descriptions, so the baseline is 3. The tool description adds no additional parameter context (e.g., examples or relationships), but it doesn't need to since the schema already handles this dimension.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Fetch') and resource ('documentation or reference page'), and explicitly states the output transformation ('return only main content as clean Markdown'). It distinguishes itself from the sibling tool read_url by specifying 'for general web pages use read_url', making the purpose unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use this tool ('for API docs, guides, and reference pages') and when to use the alternative ('For general web pages use read_url'). This gives clear context and directly addresses tool selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_urlRead URL as MarkdownA

Fetch a web page and return its content as clean, LLM-ready Markdown. Full content by default (no truncation). Handles HTML, plain text, Markdown, and JSON responses. JavaScript-heavy pages are rendered automatically in a real browser when the static HTML is an empty SPA shell. Returns an honest typed error when the site blocks access or the content cannot be read — it never silently returns partial or fake content.

ParametersJSON Schema
NameRequiredDescriptionDefault
rawNoIf true, return the raw page HTML instead of extracted Markdown. Default: false.
urlYesThe URL to fetch (http or https).
renderNoJS rendering in a real browser: true = always render, false = never render. Default: automatic — renders only when the static HTML turns out to be an empty SPA shell.
headersNoExtra HTTP headers to send, e.g. an Authorization bearer token or a Cookie for pages behind a login. Example: {"Authorization": "Bearer ...", "Cookie": "session=..."}.
max_lengthNoMaximum number of characters to return. Default 0 = unlimited (full page). If output is truncated, the response says so and tells you how to continue.
start_indexNoCharacter offset to start from, for paging through a long page. Default: 0.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It explicitly states that content is not truncated by default, formats served, automatic JS rendering behavior, and that it returns an honest typed error rather than silently returning partial or fake content. This is highly transparent, though it omits some details like rate limits or redirect handling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the primary purpose, followed by key behavioral details. Every sentence earns its place, covering formats, rendering, and error handling without unnecessary fluff. Structurally ideal for quick parsing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (6 parameters, nested objects, no output schema or annotations), the description covers the essential behavioral aspects: return format, default truncation behavior, handled content types, automatic rendering, and error honesty. The schema handles parameter details, and the description provides sufficient operational context, leaving only minor gaps like timeouts or redirects.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers 100% of parameters with detailed descriptions, so the baseline is 3. The description adds some context (e.g., 'Full content by default (no truncation)' aligns with max_length, and SPA shell behavior relates to render), but it does not provide substantial meaning beyond what the schema already offers.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool fetches a web page and returns its content as clean, LLM-ready Markdown, which is a specific verb and resource. However, it does not explicitly differentiate from the sibling tool 'read_docs', so it misses the highest mark for sibling distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage contexts (e.g., handling HTML, plain text, Markdown, JSON, and automatic JS rendering for SPAs) but provides no explicit guidance on when to use this tool versus 'read_docs' or any exclusions. It gives clear context but no direct alternative comparison.

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. Dates show when Glama detected each change.

  1. 2 tool updatesv0.1.1
    • First observedread_docs
    • First observedread_url

TDQS

A4.1/5.0
Disambiguation5/5

The two tools have clearly distinct purposes: read_url fetches any web page as full content, while read_docs is specifically for documentation pages and strips chrome. The descriptions explicitly call out when to use each, eliminating ambiguity.

Naming Consistency5/5

Both tools follow the same verb_noun pattern (read_url, read_docs), making the naming predictable and intuitive. No mixed conventions or vague verbs.

Tool Count3/5

With only 2 tools, the server feels slightly thin, but the narrow purpose (fetching and converting web content) justifies such a small surface. It borders on the low end of the ideal range but is not egregiously insufficient.

Completeness5/5

The tool set covers the core needs of fetching and reading web content comprehensively: general pages, documentation pages, and handling of multiple formats including JS-rendered content. No obvious missing operations for the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Fetches web pages and converts them to markdown for LLM consumption, supporting chunked reading and raw content extraction.
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Fetches webpages with JavaScript rendering, converts HTML to clean Markdown for LLM analysis, and uses stealth plugins to avoid bot detection.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Converts any webpage into clean, LLM-ready Markdown, removing noise and supporting JavaScript rendering.
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/labtoolsstudio/fetchmcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server