mcp-server-fetch: missing Content-Type header forces non-HTML payloads into readability extraction, failing with error
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
調査の方向性
src/fetch/src/mcp_server_fetch/server.pyの335~341行付近にあるコンテンツタイプのチェックから始め、生のコンテンツを返す経路と比較してください。コンテンツタイプのないHTMLレスポンスが現在どのように認識されているかを確認し、ヘッダーがないHTMLおよび非HTMLレスポンスを対象としたテストを実行するか追加してください。非HTMLペイロードが生のまま返され、HTMLは引き続き簡略化されることが完了条件です。
索引モデルが issue の本文から書いたものです。
説明
Which server?
fetch (mcp-server-fetch)
Server version
2026.10.10 (PyPI / commit bbb701e)
How did you run the server?
uvx (Python package)
Transport
stdio
Protocol era
Current (2024-11-05 spec or newer)
MCP client and version
Direct reproduction script / Claude Desktop 0.8.0
Operating system and runtime
Linux 5.15 / Python 3.11
Server configuration
Standard mcp-server-fetch execution.
Steps to reproduce
In src/fetch/src/mcp_server_fetch/server.py lines 335–341:
content_type = response.headers.get("content-type", "")
is_page_html = (
"<html" in page_raw[:100] or "text/html" in content_type or not content_type
)
if is_page_html and not force_raw:
return extract_content_from_html(page_raw), ""
Notice the clause or not content_type.
When fetching an HTTP endpoint that does not include an explicit Content-Type header (common with static files, raw S3/CDN buckets, embedded/IoT servers, or internal microservices returning plain text or raw JSON):
response.headers.get("content-type", "")returns"".not content_typeevaluates toTrue.is_page_htmlbecomesTrueregardless of what the payload actually contains.extract_content_from_html(page_raw)is invoked on non-HTML content (e.g. JSON{"status": 200}, plain text, CSV, or Markdown).readabilipy.simple_json.simple_json_from_html_string()cannot extract readability content from non-HTML text.- The tool returns
<error>Page failed to be simplified from HTML</error>instead of returning the raw payload.
Contrast this with the exact same payload returned with Content-Type: text/plain:
- With
Content-Type: text/plain:is_page_htmlisFalse-> returnspage_rawsuccessfully. - Without
Content-Typeheader:is_page_htmlisTrue-> fails with<error>Page failed to be simplified from HTML</error>.
Minimal reproduction:
def classify_page(page_raw: str, content_type: str):
is_page_html = (
"<html" in page_raw[:100] or "text/html" in content_type or not content_type
)
return is_page_html
# text/plain with header: False -> raw content returned
assert classify_page("hello world", "text/plain") is False
# plain text without header: True -> wrongly forced into HTML extractor!
assert classify_page("hello world", "") is True
# JSON without header: True -> wrongly forced into HTML extractor!
assert classify_page('{"status": "ok"}', "") is True
Expected behavior
Responses lacking a Content-Type header should NOT automatically be assumed to be HTML. Unless the payload contains unambiguous HTML markup (e.g. starting with <!DOCTYPE html or <html), it should be treated as non-HTML and fall back to returning page_raw.
Actual behavior
Any non-HTML endpoint without a Content-Type header is coerced into HTML simplification and fails with:
<error>Page failed to be simplified from HTML</error>
Logs or error output
<error>Page failed to be simplified from HTML</error>
From src/fetch/src/mcp_server_fetch/server.py:158-160:
ret = readabilipy.simple_json.simple_json_from_html_string(html, use_readability=True)
if not ret["content"]:
return "<error>Page failed to be simplified from HTML</error>"
Already prototyped a fix?
In src/fetch/src/mcp_server_fetch/server.py, remove or not content_type and check for HTML markers properly:
content_type_lower = content_type.lower()
page_start = page_raw.lstrip()[:100].lower()
is_page_html = (
"text/html" in content_type_lower
or "application/xhtml+xml" in content_type_lower
or page_start.startswith(("<html", "<!doctype html"))
)
This ensures:
- Valid HTML documents (with or without headers) are still simplified.
- Payloads without a
Content-Typeheader that are NOT HTML fall through to the raw content return block instead of returning an error string.
Before you submit
- I searched existing issues and this is not a duplicate.
- This is not a security vulnerability report (those go through the private advisory form).
- 主要言語
- JavaScript
- スター
- 91.2k
- フォーク
- 11.8k
- 平均マージ
- 6時間 39分
- マージ済み PR(30日)
- 111
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
modelcontextprotocol/servers のほかの issue
-
documentation v2
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
modelcontextprotocol/servers#5133 ·
メンテナーはふだん 1 日以内に返信
-
sequentialthinking: the thought box's header row is 2 columns narrower than its border対応中かも @nightcityblade が 2 日前に担当しました。 オープンbug server-sequentialthinking v2
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
modelcontextprotocol/servers#5108 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
bug server-git v2
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
modelcontextprotocol/servers#5107 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
modelcontextprotocol/servers#5071 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
modelcontextprotocol/servers#5059 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
modelcontextprotocol/servers の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
apache/rocketmq-dashboard#6610 ·
メンテナーはふだん 3 日以内に返信
-
ACK_WAITING HELP_WANTED UPDATE_CS
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
OWASP/CheatSheetSeries#2781 ·
メンテナーはふだん 1 日以内に返信
-
Hermes: /ponytail off never reaches the model, the ruleset stays active対応中かも @szsunyuan が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
DietrichGebert/ponytail#1121 ·
メンテナーはふだん 3 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
integrations plugin
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
メンテナーはふだん 1 日以内に返信