fetch-mcpCAUTION
Comprehensive HTTP fetch MCP server with SSRF protection, HTML-to-markdown, and robots.txt awareness
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
[](https://yaw.sh/mcp/install?name=Fetch&command=npx&args=-y%2C%40yawlabs%2Ffetch-mcp&description=HTTP%20fetch%20for%20AI%20agents%20-%20HTML-to-markdown%2C%20reader%20mode%2C%20metadata%2C%20RSS%2C%20sitemaps&source=https%3A%2F%2Fgithub.com%2FYawLabs%2Ffetch-mcp)
One click adds this to your local Yaw MCP config so it's available in every Yaw Terminal session. Or install manually below.
A comprehensive HTTP fetch MCP server for AI assistants. Bring-your-own client: runs as a stdio MCP server so any MCP-compatible client (Claude Code, Claude Desktop, Cursor, mcph, ...) can fetch web content safely.
What it gives the model
Safety
SSRF protection is on by default. The server refuses requests to:
- Loopback (
127.0.0.0/8,::1) - RFC1918 private ranges (
10/8,172.16/12,192.168/16) - Link-local (
169.254/16,fe80::/10) — including the cloud metadata endpoint `
13bb7c181b47OBSERVED · 2026-10-11Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.
claude mcp add fetch-mcp -- npx -y @yawlabs/[email protected]
Exposed tools (15)
11 read · 3 write · 1 destructive. Blast radius: 1 tool can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
fetch_feed | read | Fetch and parse an RSS 2.0 or Atom 1.0 feed. Returns feed-level metadata (title, description, link, updated) plus a list of entries (title, link, id, published, updated, author, summary, content, contentType, categories). Auto-detects RSS vs Atom. |
fetch_html_to_markdown | read | |
fetch_html_to_text | read | GET a URL, decode the HTML, and return plain text with block-level structure preserved as newlines. Scripts, styles, and comments stripped; HTML entities decoded. Lighter than markdown when you only need the reading content. |
fetch_links | read | |
fetch_meta | read | |
fetch_reader | read | |
fetch_robots | read | |
fetch_sitemap | read | |
http_delete | destructive | Perform an HTTP DELETE. Idempotent (per spec): a repeated DELETE on an already-deleted resource typically returns 404/410. |
http_get | read | |
http_head | read | Perform an HTTP HEAD. Returns status + headers with no body. Useful for checking a resource exists, getting its size (Content-Length), or polling for changes cheaply. |
http_options | read | Perform an HTTP OPTIONS. Returns the server |
http_patch | write | Perform an HTTP PATCH. Use for partial updates. Spec-wise NOT guaranteed idempotent — depends on the server |
http_post | write | Perform an HTTP POST. Body can be given as a raw string (body) or as a JSON value (body_json — auto-sets content-type to application/json). NOT idempotent: calling twice submits twice. |
http_put | write | Perform an HTTP PUT. Use for full-resource replacement. Idempotent: the same PUT applied twice leaves the resource in the same state. |
Trust audit
CAUTIONgrade C · trust 80/100 Install with care. The audit found things worth knowing before you trust its output.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (2 observation(s))
- Network
- declared (5 observation(s))
- Shell
- declared (4 observation(s))
- Dependencies
- not all pinned
- Secrets in source
- none-found
Findings (21)
const SSH = 'ssh -i ~/.ssh/gh_woods -o IdentitiesOnly=yes';
http_delete
return new Function(`${pieces}\nreturn runtimePlan;`)() as RuntimePlan;return new Function(`${pieces}\nreturn { pickNewest, floor: OAM_MIN };`)() as {return new Function(`${pieces}\nreturn fallbackInProcess;`)() as (hostOam: string | undefined) => boolean;const parse = new Function(
const parse = new Function(
- **SSRF: a redirect to a literal blocked IP, or to a non-http(s) scheme, is now refused. Every redirect hop runs the pre-flight URL validator.** `validateUrl()` -- scheme allow-list, literal-IP block
- **`allow_private_hosts` now needs the operator's opt-in: `FETCH_MCP_ALLOW_PRIVATE_HOSTS=1`. Breaking for anyone who relied on the per-call flag alone.** The flag is a tool argument on all 15 tools,
- **SSRF protection on by default** — blocks loopback, RFC1918 private ranges, link-local (incl. `169.254.169.254` cloud metadata), CGNAT, unique-local IPv6, multicast, IPv4-mapped IPv6 (re-checked),
2. **Per-hop redirect re-validation.** `sendHop()` in `src/http.ts` MUST run `validateUrl()` on every URL it dials (scheme allow-list, literal-IP block list, `localhost*`) AND resolve DNS + re-run `ch
- Link-local (`169.254/16`, `fe80::/10`) — including the cloud metadata endpoint `169.254.169.254`
- **SSRF: a redirect to a literal blocked IP, or to a non-http(s) scheme, is now refused. Every redirect hop runs the pre-flight URL validator.** `validateUrl()` -- scheme allow-list, literal-IP block
- **`allow_private_hosts` now needs the operator's opt-in: `FETCH_MCP_ALLOW_PRIVATE_HOSTS=1`. Breaking for anyone who relied on the per-call flag alone.** The flag is a tool argument on all 15 tools,
- **SSRF protection on by default** — blocks loopback, RFC1918 private ranges, link-local (incl. `169.254.169.254` cloud metadata), CGNAT, unique-local IPv6, multicast, IPv4-mapped IPv6 (re-checked),
2. **Per-hop redirect re-validation.** `sendHop()` in `src/http.ts` MUST run `validateUrl()` on every URL it dials (scheme allow-list, literal-IP block list, `localhost*`) AND resolve DNS + re-run `ch
Every redirect hop is re-validated against all of the above -- scheme, literal IP and `localhost*` -- before it is dialed, so a 302 from a public host to `http://127.0.0.1`, `http://169.254.169.254` o
@modelcontextprotocol/sdk, fast-xml-parser, undici, zod, @biomejs/biome, @types/node, @yawlabs/mcp-compliance, esbuild
- **The MCP SDK moves from 1.30.0 to 1.32.1** (GHSA-6qxp-vccf-f47h, high: the SDK's OAuth client could send credentials to an authorization server chosen by the MCP server; this server does not import
- **The launcher refuses to serve on a Node older than 22.19.0 with a clear message, instead of crashing.** undici 8's floor is Node 22.19.0. Below it the failure was never clean: Node 20 died at impo
The MCP host (your editor, your agent) runs this server. An LLM talks to the server over stdio and can call tools with arguments the LLM itself chose. The LLM is **not trusted** -- a malicious prompt
Gates applied: no_behavioural_pass.
13bb7c181b47full audit observations/trust-audit/mcp-server/yawlabs__fetch-mcp.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-11 | 13bb7c181b47 | CAUTION | C | 80 | first audit |
Questions
What is the fetch-mcp MCP server?
Comprehensive HTTP fetch MCP server with SSRF protection, HTML-to-markdown, and robots.txt awareness
What tools does fetch-mcp expose?
15 in total: 11 read-only, 3 that write, and 1 that can delete or overwrite (http_delete). Every one is listed on this page with its risk.
Is fetch-mcp safe to connect to an agent?
With care. The audit graded it C (80/100) and found 21 things worth knowing before you trust this server, listed below with the exact line each was found on. Separately from the audit: 1 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does fetch-mcp need?
It reads GH_TOKEN and GITHUB_TOKEN from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How does fetch-mcp run?
It speaks stdio, so it runs as a local process your client starts. It is published on npm as @yawlabs/fetch-mcp at 0.8.4.
How current is this page?
The grade is for one exact copy of the source (13bb7c181b47), read on 2026-10-11. The repository is watched and re-audited when it changes.