Fetch MCP Server

io.github.YawLabs由 GitHub 帳號 YawLabs 發布v0.8.6更新於 Oct 31, 2026

HTTP fetch MCP server: SSRF protection, HTML-to-markdown, reader mode, metadata extraction

概覽

AI 產生的概覽

本機 stdio MCP 伺服器,讓助理發出 HTTP 請求,並把網頁、訂閱源、網站地圖與 robots.txt 轉成乾淨的文字、Markdown 與中繼資料。

可以做什麼
  • 以任意方法(GET、POST、PUT、PATCH、DELETE、HEAD、OPTIONS)發出 HTTP 請求,支援自訂標頭、Basic 或 Bearer 驗證、逾時、大小上限與重試
  • 把抓取的 HTML 轉成乾淨的 Markdown 或純文字,或以閱讀模式只擷取正文
  • 擷取頁面 head 中繼資料:標題、描述、canonical、Open Graph、Twitter Card、JSON-LD、圖示與訂閱源連結
  • 擷取頁面所有外部連結,解析為絕對網址並區分站內與站外
  • 解析 sitemap.xml(含 gzip 與 sitemap-index 串接展開)以及 RSS 2.0 或 Atom 訂閱源
  • 檢查網站的 robots.txt,並針對指定路徑與 user-agent 給出允許或拒絕的判定
適用情境
適合助理需要閱讀網頁、把文章正文或中繼資料放進上下文、檢視 API,或走訪網站地圖與訂閱源的情境。適用於本機 MCP 用戶端中的資料蒐集、內容擷取與輕量 API 測試。
執行需求
以 stdio 方式在本機執行,通常透過 npx 或全域 npm 安裝;在 Node 上執行需要 Node 22.19 或更新版本。未宣告任何帳號、API 金鑰或標頭。需要能連線到目標主機的網路。若要存取私有或回送位址,維運方還須設定 FETCH_MCP_ALLOW_PRIVATE_HOSTS。
安裝前請注意
寫入方法(POST、PUT、PATCH、DELETE)可能變更或刪除遠端資料,且 POST 不具冪等性。透過 basic_auth 或 bearer_token 傳入的憑證會送往目標主機,驗證標頭僅在跨來源重新導向時被移除。開啟 FETCH_MCP_ALLOW_PRIVATE_HOSTS 會讓遭提示注入的請求觸及內網與雲端中繼資料端點,在雲端虛擬機上應保持關閉。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Fetch MCP Server,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

@yawlabs/fetch-mcp

[Add to Yaw 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

ToolWhat it does
http_get / http_head / http_optionsBare HTTP requests with headers, auth, timeout, size cap, retry
http_post / http_put / http_patch / http_deleteWrite-method HTTP with JSON or raw body
fetch_html_to_markdownGET a page and convert to clean markdown (3–8× smaller than raw HTML)
fetch_html_to_textGET a page and convert to plain text with block structure preserved
fetch_readerReader-mode extraction — isolates the article body and returns title + markdown
fetch_metaExtract <head> metadata: title, description, OpenGraph, Twitter cards, JSON-LD, feeds, icons
fetch_linksExtract every outbound link, resolved to absolute URLs, classified internal/external
fetch_sitemapParse sitemap.xml (including gzipped and sitemap-index chaining)
fetch_feedParse an RSS 2.0 or Atom 1.0 feed into entries
fetch_robotsParse a site's robots.txt, return the verdict for a given path & user-agent

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 169.254.169.254
  • CGNAT (100.64/10)
  • Unique-local IPv6 (fc00::/7)
  • Multicast / broadcast
  • IPv4-mapped IPv6 (::ffff:0:0/96) re-checked against the IPv4 rules, and likewise the IPv4 embedded in IPv4-compatible (::/96), IPv4-translated (::ffff:0:0:0/96) and 6to4 (2002::/16) addresses
  • Teredo (2001::/32), NAT64 (64:ff9b::/96, 64:ff9b:1::/48), site-local (fec0::/10) and discard-only (100::/64) IPv6
  • Any other IPv6 outside global unicast (2000::/3), and the non-global blocks inside it (3fff::/20, 2001:2::/48, 2001:10::/28)
  • The Azure WireServer address 168.63.129.16
  • Non-http/https schemes (file://, gopher://, javascript:, …)
  • Hostname localhost and any *.localhost

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 or ftp://… is caught. For hostnames, DNS is resolved once per hop, every returned address is checked, and the verified IP is pinned into the HTTP dispatcher so the subsequent TCP connection dials that exact address — closing the DNS-rebinding TOCTOU window. Authorization, Cookie and Proxy-Authorization headers are stripped on cross-origin redirects.

Reaching private hosts (development)

The model chooses tool arguments, and the model is not trusted: a prompt injected through a fetched page can ask for anything. So the per-call allow_private_hosts: true opt-in is refused unless the operator enables it by launching the server with FETCH_MCP_ALLOW_PRIVATE_HOSTS=1 (true/yes/on also work; any unrecognised value is treated as off and named on stderr). With the variable set, a call still has to ask: requests without allow_private_hosts stay guarded.

json
{  "mcpServers": {    "fetch": {      "command": "npx",      "args": ["-y", "@yawlabs/fetch-mcp@latest"],      "env": { "FETCH_MCP_ALLOW_PRIVATE_HOSTS": "1" }    }  }}

Only set it where the model may legitimately reach your internal network -- a local dev box, not a cloud VM with a metadata endpoint.

Install & run

bash
# One-off (auto-updates each spawn via @latest)npx -y @yawlabs/fetch-mcp@latest
# Or globallynpm i -g @yawlabs/fetch-mcpfetch-mcp

Requires Node 22.19 or newer when running on Node (the floor of its HTTP client, undici 8; the launcher refuses older Nodes with a clear message instead of crashing). Under oam, which the launcher prefers when installed, the Node version does not matter.

Configure in Claude Code / Claude Desktop

Add to your client's MCP config (usually claude_desktop_config.json or ~/.claude.json):

json
{  "mcpServers": {    "fetch": {      "command": "npx",      "args": ["-y", "@yawlabs/fetch-mcp@latest"]    }  }}

Or via mcph:

bash
mcph add fetch

Tool reference

http_get, http_post, http_put, http_patch, http_delete, http_head, http_options

Common parameters:

FieldTypeDefaultMeaning
urlstring—Absolute URL
headersobject—Custom request headers
timeout_msint10000Timeout for each attempt, covering DNS, every redirect hop and the body. Retries get a fresh budget; a whole call is capped at 5 minutes. Cancelling the tool call stops the request
max_bytesint5242880 (5 MiB)Truncate body if larger
max_redirectsint5Redirect hops allowed
retriesint0Retry count on 408/425/429/5xx with backoff (honors Retry-After)
user_agentstring@yawlabs/fetch-mcp/<v>User-Agent override
basic_auth{username,password}—Injects Authorization: Basic …
bearer_tokenstring—Injects Authorization: Bearer …
allow_private_hostsboolfalseOpt this call into loopback / private / link-local targets. Refused unless the operator set FETCH_MCP_ALLOW_PRIVATE_HOSTS=1 (details)
decode_textboolautoWhen unset, auto-detects by response Content-Type (text for text/*, JSON, XML, JS, form-urlencoded; binary otherwise). Set explicitly true to force text decoding, false to force base64 in body_base64.

Body-capable tools (POST/PUT/PATCH/DELETE) also take:

FieldTypeMeaning
bodystringRaw request body
body_jsonanyStructured body — encoded as JSON, Content-Type: application/json set automatically
content_typestringOverrides Content-Type

Response shape:

ts
{  ok: boolean;  status: number;  statusText: string;  url: string;              // final URL after redirects  headers: Record<string,string>;  body_text?: string;  body_base64?: string;     // when decode_text=false  json?: unknown;           // auto-parsed when response is application/json  truncated?: boolean;      // set when max_bytes hit  redirects?: string[];     // chain of intermediate URLs  duration_ms: number;  error?: string;}

fetch_html_to_markdown

GET the URL, strip scripts/styles/iframes/svg/canvas plus <nav>, <footer>, <aside>, convert to atx-headed markdown with fenced code blocks and dash bullets. Intended for feeding pages into an LLM without blowing the context budget.

fetch_html_to_text

Same fetch, but emits plain text with block-level structure preserved as newlines. Useful when the model doesn't need markdown formatting.

fetch_reader

Isolates the main article body using, in order: <article>, <main>, itemprop="articleBody", common CMS class names (post-content, entry-content, etc.), then <body> as fallback. Returns:

ts
{  url: string;          // final URL after redirects  title?: string;       // og:title, then <title>, then <h1>  byline?: string;      // meta[name=author] / article:author  wordCount: number;  markdown: string;     // main content converted to markdown}

fetch_meta

GET a URL and return its head metadata without downloading the full body (caps at 2 MiB by default):

ts
{  url: string;  title?: string;  description?: string;  canonical?: string;  language?: string;  robots?: string;  og:      Record<string, string>;       // first value per key (og:title, og:image, og:type, ...)  twitter: Record<string, string>;       // first value per key  article: Record<string, string>;       // first value per key  ogAll:      Record<string, string[]>;  // only keys that appear > once (e.g. multiple og:image)  twitterAll: Record<string, string[]>;  articleAll: Record<string, string[]>;  icons:   Array<{ rel: string; href: string; sizes?: string }>;  feeds:   Array<{ href: string; title?: string; type?: string }>;   // RSS/Atom  jsonLd:  unknown[];                    // parsed application/ld+json blocks}

fetch_links

GET a page and return every <a href> with text, resolved to absolute URLs. Respects <base href>. Skips #, javascript:, mailto:, tel:, data:, file:. Each link is classified internal or external vs. the page host. Optional filter/dedupe/limit.

fetch_sitemap

Fetch a sitemap.xml or sitemap-index and return the URL list:

ts
{  sitemaps: string[];       // indexes followed, in order  urlCount: number;  truncated: boolean;       // hit max_urls  childSitemaps: string[];  // listed but not fetched (past max_depth or max_sitemaps)  warnings: Array<{ url: string; error: string }>;  urls: Array<{    loc: string;    lastmod?: string;    changefreq?: string;    priority?: number;  }>;}

Gzipped .xml.gz sitemaps are auto-decompressed. max_depth controls how many levels of sitemap-index to follow (default 1). Setting max_depth: 0 on a sitemap-index returns the index's childSitemaps list without fetching any child (useful to discover structure cheaply). Partial failures — one child sitemap 500s while others succeed — are returned under warnings rather than aborting the whole call. max_sitemaps (default 50, max 1000) caps how many sitemap documents one call fetches, index included; children past it are listed under childSitemaps with a warning. The whole call is capped at 5 minutes. max_bytes (default 20 MiB) applies to each sitemap, and to the decompressed size of a gzipped one; a sitemap larger than that is an error (a warning for a child) rather than a silently partial URL list.

fetch_feed

Parse an RSS 2.0 or Atom 1.0 feed:

ts
{  kind: "rss" | "atom" | "unknown";  title?: string;  description?: string;  link?: string;  updated?: string;  entryCount: number;  truncated: boolean;       // hit limit  entries: Array<{    title?: string;    link?: string;    id?: string;    published?: string;    updated?: string;    author?: string;    summary?: string;    content?: string;    categories?: string[];  }>;}

fetch_robots

Fetches <origin>/robots.txt, parses it, and returns:

ts
{  robotsUrl: string;  status: number;  userAgent: string;  path: string;  allowed: boolean;  matchedRule: string | null;  // the longest-match Allow/Disallow that decided it  crawlDelay: number | null;   // from the matched group  sitemaps: string[];          // top-level Sitemap: declarations  rawRobotsText: string;       // first 512KB  note?: string;               // only when robots.txt 404s}

A /robots.txt that returns 404 means there are no rules, so the verdict is allowed: true. The response keeps the same shape: status: 404, matchedRule: null, crawlDelay: null, sitemaps: [], rawRobotsText: "", plus the note. Any other non-2xx status is returned as an error.

The parser follows Google's rules: longest match wins, * is a wildcard segment, $ anchors the end of the path, specific user-agent group beats the * wildcard group when the UA matches (comparison uses the length of the actually-matched agent token, not the group's first agent). Allow beats Disallow on equal-length ties.

Development

bash
npm installnpm run buildnpm test         # vitestnpm run lint     # biomenpm run typecheck

Tests spin up a local loopback HTTP server on 127.0.0.1:0 to exercise the real request/response path — no mocking of HTTP. SSRF tests verify that the default-deny still applies to that local server unless the operator gate is on and the request opts into allow_private_hosts.

License

MIT © Yaw Labs

Links

[Follow @YawLabs on X]

來源:README.md,提交 4e76a9d

工具

15

http_get

Perform an HTTP GET. Returns status, headers, and body. Automatically parses JSON when the server responds with application/json. Follows redirects (each hop re-validated against SSRF rules). Refuses URLs that resolve to private/loopback/link-local addresses unless the operator enabled FETCH_MCP_ALLOW_PRIVATE_HOSTS and the call sets allow_private_hosts.

輸入參數url必填headersretriesmax_bytesbasic_authtimeout_msuser_agentdecode_textbearer_tokenmax_redirectsallow_private_hosts

http_post

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.

輸入參數url必填bodyheadersretriesbody_jsonmax_bytesbasic_authtimeout_msuser_agentdecode_textbearer_tokencontent_type另有 2 個

http_put

Perform an HTTP PUT. Use for full-resource replacement. Idempotent: the same PUT applied twice leaves the resource in the same state.

輸入參數url必填bodyheadersretriesbody_jsonmax_bytesbasic_authtimeout_msuser_agentdecode_textbearer_tokencontent_type另有 2 個

http_patch

Perform an HTTP PATCH. Use for partial updates. Spec-wise NOT guaranteed idempotent — depends on the server's patch semantics.

輸入參數url必填bodyheadersretriesbody_jsonmax_bytesbasic_authtimeout_msuser_agentdecode_textbearer_tokencontent_type另有 2 個

http_delete

Perform an HTTP DELETE. Idempotent (per spec): a repeated DELETE on an already-deleted resource typically returns 404/410.

輸入參數url必填bodyheadersretriesbody_jsonmax_bytesbasic_authtimeout_msuser_agentdecode_textbearer_tokencontent_type另有 2 個

http_head

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.

輸入參數url必填headersretriesmax_bytesbasic_authtimeout_msuser_agentdecode_textbearer_tokenmax_redirectsallow_private_hosts

http_options

Perform an HTTP OPTIONS. Returns the server's supported methods and CORS policy for a resource. Helpful for API discovery.

輸入參數url必填headersretriesmax_bytesbasic_authtimeout_msuser_agentdecode_textbearer_tokenmax_redirectsallow_private_hosts

fetch_html_to_markdown

GET a URL, decode the HTML, and convert to clean markdown (headings, lists, links, code fences). Scripts, styles, iframes, nav, footer, and aside elements are stripped. Intended for feeding web pages into an LLM cheaply -- markdown is usually 3-8x smaller than raw HTML. Follows redirects, respects size/timeout limits, and blocks private-host requests by default.

輸入參數url必填max_bytestimeout_msuser_agentmax_redirectsallow_private_hosts

fetch_html_to_text

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.

輸入參數url必填max_bytestimeout_msuser_agentmax_redirectsallow_private_hosts

fetch_robots

Fetch and parse the robots.txt for a given origin, then tell the caller whether a target URL is crawlable by a given user-agent. Follows the Google-style longest-match rule with Allow-wins-on-tie. Returns the raw robots.txt, parsed groups, sitemap references, and the allow/deny verdict with the matching rule.

輸入參數url必填timeout_msuser_agentmax_redirectsallow_private_hosts

fetch_sitemap

Fetch a sitemap.xml (or sitemap-index) and return the contained URLs with their lastmod / changefreq / priority. Follows sitemap-index chaining up to max_depth levels. Gzipped .xml.gz payloads are auto-decompressed. A single sitemap document over 16 MiB once decoded is refused (a 50,000-URL sitemap is ~11 MiB). Partial failures (one child sitemap 500s while others work) are returned under 'warnings' without aborting the whole request. SSRF-protected by default.

輸入參數url必填max_urlsmax_bytesmax_depthtimeout_msuser_agentmax_sitemapsmax_redirectsallow_private_hosts

fetch_meta

GET a URL and extract its head metadata: title, description, canonical, language, robots directive, Open Graph / Twitter Card / article: properties, icon links, RSS/Atom feed links, and any JSON-LD (schema.org) blocks. Keys that appear more than once (e.g. multiple og:image tags) are additionally returned via ogAll/twitterAll/articleAll arrays. Lists are capped: at most 100 icons, feeds, JSON-LD blocks and values per *All key, and 1000 keys per og/twitter/article; a JSON-LD block nested deeper than 64 levels is dropped. When anything is cut, `truncated` names the collections affected. Ideal for previewing a page before fully reading it.

輸入參數url必填max_bytestimeout_msuser_agentmax_redirectsallow_private_hosts

fetch_feed

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.

輸入參數url必填limitmax_bytestimeout_msuser_agentmax_redirectsallow_private_hosts

fetch_reader

GET a URL, locate the main article body (prefers <article>, <main>, itemprop=articleBody, or known CMS class names; falls back to <body>), strip navigation/footer/aside chrome, and convert to clean markdown. Returns { title, byline, markdown, wordCount }. Optimized for feeding long-form articles into an LLM without header/footer/sidebar noise.

輸入參數url必填max_bytestimeout_msuser_agentmax_redirectsallow_private_hosts

版本歷史

10
  1. v0.8.6最新Oct 31, 2026
  2. v0.8.5Oct 11, 2026
  3. v0.8.4Oct 8, 2026
  4. v0.8.3Oct 7, 2026
  5. v0.8.2Sep 30, 2026
  6. v0.8.1Sep 24, 2026
  7. v0.8.0Sep 22, 2026
  8. v0.7.1Sep 21, 2026
  9. v0.7.0Sep 17, 2026
  10. v0.6.2Sep 16, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分
  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分