Fetch MCP Server について
Fetch MCP Serverは、stdioサーバーを通じてAIアシスタントがHTTPリクエストを送り、ウェブコンテンツを抽出できるようにします。HTML変換やサイトメタデータのツールに加え、リダイレクト先や解決済みアドレスも検査するSSRF対策を標準で備えています。
主な機能
- 01ヘッダー、認証、再試行に対応するHTTPメソッド
- 02HTMLをMarkdownや構造化テキストに変換
- 03本文、メタデータ、リンクの抽出
- 04サイトマップ、RSS/Atomフィード、robots.txtの解析
- 05リクエストとリダイレクトのSSRF検査
活用シーン
- 01AIアシスタントのコンテキストとしてウェブページを取得
- 02記事本文とページメタデータを抽出
- 03サイトマップ、フィード、クロール規則を確認
MCP 対応
stdioで動作するMCPサーバーとして、MCP対応クライアントにHTTPリクエストとウェブ抽出のツールを提供します。標準でSSRF対策を有効にし、リダイレクト先を逐一検査します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
15掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| url | string | はい | 対象 URL(http:// または https://) |
| headers | object | いいえ | 追加のリクエストヘッダーをキーと値のオブジェクトで指定します |
| retries | integer | いいえ | 408/425/429/500/502/503/504 の場合に指数バックオフで再試行します(デフォルト 0) |
| max_bytes | integer | いいえ | レスポンス本文を切り詰める前の最大サイズ(バイト)(デフォルト 5MiB、上限 100MiB) |
| basic_auth | object | いいえ | HTTP Basic 認証情報 |
| basic_auth.password | string | はい | |
| basic_auth.username | string | はい | |
| timeout_ms | integer | いいえ | 各試行のタイムアウト(ミリ秒)。DNS、各リダイレクトホップ、本文を対象とします(デフォルト 10000、最大 120000)。再試行には新しい時間枠が割り当てられ、呼び出し全体の上限は 5 分です。 |
| user_agent | string | いいえ | User-Agent を上書きします(デフォルトでは @yawlabs/fetch-mcp として識別) |
| decode_text | boolean | いいえ | テキストデコード(true)またはバイナリ base64(false)を強制します。デフォルトは自動で、text/*、json、xml などはテキスト、それ以外はバイナリです。 |
| bearer_token | string | いいえ | Authorization: Bearer <token> として送信する Bearer トークン |
| max_redirects | integer | いいえ | 追跡するリダイレクトの最大ホップ数(デフォルト 5) |
| allow_private_hosts | boolean | いいえ | この呼び出しでループバック/プライベート/リンクローカルの宛先を許可します(デフォルト false)。サーバーオペレーターが FETCH_MCP_ALLOW_PRIVATE_HOSTS=1 を指定して fetch-mcp を起動していない場合は拒否されます。いずれの場合も、SSRF 保護はデフォルトで有効です。 |
詳細
@yawlabs/fetch-mcp
ワンクリックでローカルの Yaw MCP 設定に追加でき、すべての Yaw Terminal セッションで利用できます。手動でインストールする場合は、以下をご覧ください。
AI アシスタント向けの包括的な HTTP フェッチ MCP サーバーです。クライアントは自由に選べます。stdio MCP サーバーとして動作するため、MCP 対応クライアント(Claude Code、Claude Desktop、Cursor、mcph など)で安全にウェブコンテンツを取得できます。
モデルに提供する機能
| ツール | 機能 |
|---|---|
http_get / http_head / http_options | ヘッダー、認証、タイムアウト、サイズ上限、再試行に対応した基本的な HTTP リクエスト |
http_post / http_put / http_patch / http_delete | JSON または生のボディを使った書き込み用 HTTP リクエスト |
fetch_html_to_markdown | ページを GET し、クリーンな Markdown に変換します(生の HTML より 3~8 倍小さくなります) |
fetch_html_to_text | ページを GET し、ブロック構造を保持したプレーンテキストに変換します |
fetch_reader | リーダーモードで抽出し、記事本文を切り出してタイトルと Markdown を返します |
fetch_meta | <head> のメタデータを抽出します:タイトル、説明、OpenGraph、Twitter カード、JSON-LD、フィード、アイコン |
fetch_links | すべての外部リンクを抽出し、絶対 URL に解決して、内部/外部に分類します |
fetch_sitemap | sitemap.xml を解析します(gzip 圧縮とサイトマップインデックスの連鎖にも対応) |
fetch_feed | RSS 2.0 または Atom 1.0 フィードを解析してエントリーにします |
fetch_robots | サイトの robots.txt を解析し、指定されたパスとユーザーエージェントに対する判定を返します |
安全性
SSRF 保護はデフォルトで有効です。サーバーは次の宛先へのリクエストを拒否します。
- ループバック(
127.0.0.0/8、::1) - RFC1918 プライベート範囲(
10/8、172.16/12、192.168/16) - リンクローカル(
169.254/16、fe80::/10)— クラウドのメタデータエンドポイント169.254.169.254も含みます - CGNAT(
100.64/10) - IPv6 ユニークローカル(
fc00::/7) - マルチキャスト/ブロードキャスト
- IPv4 マップ IPv6(
::ffff:0:0/96)は IPv4 のルールに照らして再確認されます。同様に、IPv4 互換(::/96)、IPv4 変換(::ffff:0:0:0/96)、6to4(2002::/16)アドレス内に埋め込まれた IPv4 も再確認されます - Teredo(
2001::/32)、NAT64(64:ff9b::/96、64:ff9b:1::/48)、サイトローカル(fec0::/10)、破棄専用(100::/64)の IPv6 - グローバルユニキャスト(
2000::/3)以外のその他すべての IPv6 と、その範囲内にある非グローバルブロック(3fff::/20、2001:2::/48、2001:10::/28) - Azure WireServer アドレス
168.63.129.16 http/https以外のスキーム(file://、gopher://、javascript:など)- ホスト名
localhostおよびすべての*.localhost
リダイレクトの各段階では、接続前に上記すべて(スキーム、リテラル IP、localhost*)を再検証するため、公開ホストから http://127.0.0.1、http://169.254.169.254、ftp://… へリダイレクトする 302 も検出されます。ホスト名については、各段階で DNS を一度だけ解決し、返されたすべてのアドレスを確認します。検証済みの IP は HTTP ディスパッチャーに固定されるため、その後の TCP 接続は必ずそのアドレスに接続され、DNS リバインディングによる TOCTOU の隙間を塞ぎます。オリジンをまたぐリダイレクトでは、Authorization、Cookie、Proxy-Authorization ヘッダーが削除されます。
プライベートホストへの接続(開発時)
モデルはツール引数を選択しますが、モデルは信頼できません。取得したページに埋め込まれたプロンプトインジェクションによって、モデルが何でも要求する可能性があります。そのため、呼び出しごとの allow_private_hosts: true オプトインは、FETCH_MCP_ALLOW_PRIVATE_HOSTS=1 を設定してサーバーを起動し、オペレーターが有効にしない限り拒否されます(true/yes/on も使用できます。認識されない値はオフとして扱われ、stderr に値が表示されます)。この変数を設定しても、呼び出し側でオプトインする必要があります。allow_private_hosts を指定しないリクエストは引き続き保護されます。
{
"mcpServers": {
"fetch": {
"command": "npx",
"args": ["-y", "@yawlabs/fetch-mcp@latest"],
"env": { "FETCH_MCP_ALLOW_PRIVATE_HOSTS": "1" }
}
}
}
モデルが内部ネットワークに正当に接続できる環境でのみ設定してください。たとえばローカルの開発マシンでは設定できますが、メタデータエンドポイントのあるクラウド VM では設定しないでください。
インストールと実行
# One-off (auto-updates each spawn via @latest)
npx -y @yawlabs/fetch-mcp@latest
# Or globally
npm i -g @yawlabs/fetch-mcp
fetch-mcp
Node で実行する場合は、Node 22.19 以降が必要です(HTTP クライアントである undici 8 が要求する最低バージョンです。ランチャーは古いバージョンの Node ではクラッシュせず、明確なメッセージを表示して起動を拒否します)。インストール済みの場合にランチャーが優先して使用する oam の下では、Node のバージョンは問いません。
Claude Code/Claude Desktop での設定
クライアントの MCP 設定(通常は claude_desktop_config.json または ~/.claude.json)に追加します。
{
"mcpServers": {
"fetch": {
"command": "npx",
"args": ["-y", "@yawlabs/fetch-mcp@latest"]
}
}
}
または、mcph を使用します。
mcph add fetch
ツールリファレンス
http_get、http_post、http_put、http_patch、http_delete、http_head、http_options
共通パラメーター:
| フィールド | 型 | デフォルト | 意味 |
|---|---|---|---|
url | string | — | 絶対 URL |
headers | object | — | カスタムリクエストヘッダー |
timeout_ms | int | 10000 | 各試行のタイムアウト。DNS、すべてのリダイレクト先、本文を対象とします。再試行ごとに新しい時間枠が設けられ、呼び出し全体は 5 分で打ち切られます。ツール呼び出しをキャンセルすると、リクエストも停止します |
max_bytes | int | 5242880(5 MiB) | 本文がこれを超える場合に切り詰めます |
max_redirects | int | 5 | 許可されるリダイレクトの回数 |
retries | int | 0 | 408/425/429/5xx の場合の再試行回数(バックオフあり。Retry-After を尊重します) |
user_agent | string | @yawlabs/fetch-mcp/<v> | User-Agent の上書き値 |
basic_auth | {username,password} | — | Authorization: Basic … を付与します |
bearer_token | string | — | Authorization: Bearer … を付与します |
allow_private_hosts | bool | false | この呼び出しでループバック/プライベート/リンクローカルの宛先を許可します。オペレーターが FETCH_MCP_ALLOW_PRIVATE_HOSTS=1 を設定していない場合は拒否されます(詳細) |
decode_text | bool | 自動 | 未設定の場合、レスポンスの Content-Type に基づいて自動判定します(text/*、JSON、XML、JS、form-urlencoded はテキスト、それ以外はバイナリ)。テキストデコードを強制するには true、body_base64 での Base64 出力を強制するには false を明示的に設定します。 |
本文を扱うツール(POST/PUT/PATCH/DELETE)では、次のパラメーターも使用できます。
| フィールド | 型 | 意味 |
|---|---|---|
body | string | 生のリクエスト本文 |
body_json | any | 構造化された本文。JSON としてエンコードされ、Content-Type: application/json が自動設定されます |
content_type | string | Content-Type を上書きします |
レスポンスの形式:
{
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
URL に GET リクエストを行い、スクリプト/スタイル/iframe/svg/canvas に加えて <nav>、<footer>、<aside> を除去し、ATX 形式の見出し、フェンス付きコードブロック、ダッシュ形式の箇条書きを使用した Markdown に変換します。コンテキストの上限を超えずにページを LLM に入力することを目的としています。
fetch_html_to_text
同じリクエストを行いますが、ブロックレベルの構造を改行で保持したプレーンテキストを出力します。モデルに Markdown の書式が不要な場合に便利です。
fetch_reader
本文を、次の順で抽出します。<article>、<main>、itemprop="articleBody"、一般的な CMS のクラス名(post-content、entry-content など)、最後にフォールバックとして <body>。返される内容:
{
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
URL に GET リクエストを行い、本文全体をダウンロードせずに head のメタデータを返します(デフォルトでは 2 MiB で上限を設定):
{
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 href> をテキストとともに絶対 URL に解決して返します。<base href> を尊重します。#、javascript:、mailto:、tel:、data:、file: は除外します。各リンクを、ページのホストと比較して internal または external に分類します。filter/dedupe/limit は任意です。
fetch_sitemap
sitemap.xml またはサイトマップインデックスを取得し、URL リストを返します:
{
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;
}>;
}
.xml.gz 形式の gzip 圧縮されたサイトマップは自動的に展開されます。max_depth は、たどるサイトマップインデックスの階層数を制御します(デフォルトは 1 です)。サイトマップインデックスで max_depth: 0 を設定すると、子を取得せずにインデックスの childSitemaps リストを返します(構造を手軽に確認するのに便利です)。一部で失敗した場合(ある子サイトマップが 500 を返し、ほかは成功した場合など)、呼び出し全体を中断せず、失敗は warnings に返されます。max_sitemaps(デフォルトは 50、最大 1000)は、インデックスを含め、1 回の呼び出しで取得するサイトマップドキュメント数の上限です。上限を超える子は、警告とともに childSitemaps に記載されます。呼び出し全体のタイムアウトは 5 分です。max_bytes(デフォルトは 20 MiB)は各サイトマップに適用され、gzip 圧縮されたサイトマップの場合は展開後のサイズに適用されます。このサイズを超えるサイトマップはエラーとなり(子の場合は警告となり)、URL リストが黙って不完全な状態で返されることはありません。
fetch_feed
RSS 2.0 または Atom 1.0 フィードを解析します:
{
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
<origin>/robots.txt を取得して解析し、次を返します:
{
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
}
/robots.txt が 404 を返す場合、ルールは存在しないものとみなされるため、判定結果は allowed: true になります。レスポンスは同じ形式を保ちます:status: 404、matchedRule: null、crawlDelay: null、sitemaps: []、rawRobotsText: "" に加えて、note が含まれます。その他の 2xx 以外のステータスはエラーとして返されます。
パーサーは Google のルールに従います。最長一致が優先され、* はワイルドカードセグメント、$ はパスの末尾を示します。UA が一致する場合は、特定のユーザーエージェントのグループが * ワイルドカードグループより優先されます(一致したグループの先頭のエージェントではなく、実際に一致したエージェントトークンの長さで比較します)。同じ長さで競合する場合は、Allow が Disallow より優先されます。
開発
npm install
npm run build
npm test # vitest
npm run lint # biome
npm run typecheck
テストでは 127.0.0.1:0 でローカルのループバック HTTP サーバーを起動し、実際のリクエスト/レスポンス経路を検証します。HTTP のモックは使用しません。SSRF テストでは、オペレーター用ゲートが有効で、リクエストに allow_private_hosts が指定されていない限り、ローカルサーバーに対してもデフォルトの拒否設定が適用されることを確認します。
ライセンス
MIT © Yaw Labs
リンク
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。