Web Speed について
Web Speedは、見出し、リンク、フォーム、表などを構造化マップに変換する、エージェント向けのMCPサーバーです。LLMによる解釈を行わず、サイトのクロールやページ分類にも対応し、ウェブ操作の計画に役立ちます。
主な機能
- 01ページの構造化マップを抽出
- 02フォーム送信後のページを解析
- 03サイトをクロールしてページマップを作成
- 04CSSセレクターで要素を検査
- 05ページ分類とキャッシュ管理
活用シーン
- 01ナビゲーションと本文リンクの抽出
- 02複数ページにまたがる操作の計画
- 03フォーム項目の確認とデータ送信
- 04リストや表内の要素の検査
MCP 対応
ページ解析、フォーム送信、サイトクロール、要素検査、ページ分類、キャッシュ無効化の6種類のウェブツールをMCPクライアントに提供します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
翻訳後に原文が更新されています。最新の内容は原文をご確認ください。
Web Speed
Web Speed は、AI エージェントのシグナル対ノイズ問題を解決します。現代のウェブは人間の目向けに最適化されていますが(雑然とした HTML、複雑なレイアウト、JavaScript を多用したインターフェース)、Web Speed はその混沌を、高スループットのエージェント群向けに設計された、決定論的でトークン効率の高い構造マップへと変換します。
AI は内部にありません。 anthropic も openai も、いかなる種類の LLM 依存関係もありません。解釈はすべて呼び出し元のエージェントが担います。
選択した LLM 用のマスター指示ファイル(gemini.md、「Instructions for Claude」など)も設定することをおすすめします。サンプルドキュメントは**こちら**にあります。
存在理由
| 問題 | Web Speed の解決策 |
|---|---|
| 生の HTML は、スクリプト、スタイル、SVG のノイズで 150,000 文字以上になる | 構造に関係のないものをすべて除去 → トークンを最大 97% 削減 |
| LLM は生の DOM で要素 ID を幻覚し、操作可能な箇所を見落とす | 固定された構造マップを返します。存在するものだけが記載され、何も捏造されません |
| カスタムスクレイパーはサイトごとに動作しなくなる | 決定論的なプロトコル — ウェブ上のすべてのサイトで同じ JSON 形式 |
| エージェントは 1 回の往復ごとにページを再発見する必要がある | site_map は 1 回の呼び出しでドメイン全体をクロールします |
ツール
| ツール | 説明 |
|---|---|
interpret_page | 完全な構造マップ:見出し、ナビゲーション、コンテンツリンク、フォーム、表、テキスト、メタデータ |
submit_form | フォーム(GET または POST)を送信し、遷移先ページのマップを取得 |
site_map | ルート URL からクロールし、すべてのページの統合マップを返す |
inspect_element | CSS セレクターに一致するノードの詳細な構造データ |
page_type | ページを即座に分類 — login、listing、article、form、navigation、other |
invalidate_cache | キャッシュ済みのマップを破棄し、次回の呼び出しで最新データを取得 |
インストール
Mac / Linux
cd web-interpreter
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Windows
cd web-interpreter
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt
実行
MCP inspector を使ったローカル開発の場合:
mcp dev server.py
stdio 経由で直接実行する場合(MCP クライアントによる起動方法):
python server.py
Claude / Cowork に登録する
~/Library/Application Support/Claude/claude_desktop_config.json(Mac)または Windows 上の同等のファイルに追加します:
{
"mcpServers": {
"web-speed": {
"command": "/absolute/path/to/web-interpreter/venv/bin/python",
"args": ["/absolute/path/to/web-interpreter/server.py"]
}
}
}
その後、Claude Desktop / Cowork を終了して再起動します。web-speed MCP サーバーの下に 6 つのツールが表示されます。
出力スキーマ
interpret_page
{
"url": "https://example.com/",
"fetched_at": "2025-01-01T12:00:00Z",
"page_type": "other",
"title": "Example Domain",
"description": "",
"headings": [
{ "level": 1, "text": "Example Domain" }
],
"navigation": [
{ "label": "Home", "url": "https://example.com/", "location": "header" }
],
"content_links": {
"total": 47,
"truncated": false,
"items": [
{ "label": "More information...", "url": "https://www.iana.org/domains/example" }
]
},
"forms": [
{
"id": "search",
"action": "https://example.com/search",
"method": "GET",
"fields": [
{
"name": "q",
"type": "text",
"label": "Search",
"placeholder": "Search...",
"required": false,
"value": ""
},
{
"name": "_csrf",
"type": "hidden",
"label": "",
"placeholder": "",
"required": false,
"value": "abc123"
}
]
}
],
"tables": [
{
"id": "results",
"headers": ["Name", "Price", "Stock"],
"rows": [["Widget A", "$9.99", "In stock"]]
}
],
"text_blocks": [
{ "tag": "p", "text": "This domain is for use in illustrative examples." }
],
"metadata": {
"lang": "en",
"canonical": "",
"open_graph": { "title": "", "description": "", "image": "" }
}
}
主なフィールド:
navigation— セマンティックな nav/header/footer 要素(サイトの共通部分、メニュー)内のリンク。上限は 60 件です。content_links— ページ本文(記事、検索結果、一覧)内のリンク。60 件で切り詰められた場合でも実際の件数がわかるよう、常にtotalが含まれます。forms— すべてのフィールドを含むすべてのフォーム。CSRF トークンは hidden フィールドのvalueにそのまま保持されます。page_type— 構造から推定:パスワードフィールド →login、多数の項目/リンク →listing、段落を含む<article>→article、フォーム →form、リンクが大半 →navigation。
page_type
軽量で、分類結果のみを返します。ページがキャッシュされていれば即座に返されます。
{
"url": "https://example.com/login",
"fetched_at": "2025-01-01T12:00:00Z",
"page_type": "login",
"title": "Sign In"
}
submit_form
送信後にサーバーが表示するページについて、interpret_page と同じ形式の出力を返します。
{
"url": "https://example.com/login",
"method": "POST",
"fields": {
"email": "[email protected]",
"password": "hunter2",
"_csrf": "abc123"
}
}
CSRF トークンは fields にそのまま指定します。直前の interpret_page 呼び出しで返された forms 配列内の hidden フィールドから取得してください。
inspect_element
CSS セレクターに一致するノードの詳細な構造データです。上限は 25 要素です。
{
"url": "https://example.com/shop",
"selector": ".product-card",
"matched": 48,
"truncated": true,
"elements": [
{
"tag": "div",
"id": "product-42",
"classes": ["product-card", "featured"],
"text": "Widget Pro $49.99 Add to cart",
"attributes": { "id": "product-42" },
"links": [{ "label": "Add to cart", "url": "https://example.com/cart/add/42" }],
"fields": [],
"children": [
{ "tag": "h3", "text": "Widget Pro" },
{ "tag": "span", "text": "$49.99" },
{ "tag": "a", "text": "Add to cart", "href": "https://example.com/cart/add/42" }
]
}
]
}
セレクターの例:#login-form、.product-card、table.results tbody tr、nav a、[data-testid="price"]
site_map
{
"root_url": "https://example.com",
"crawled_at": "2025-01-01T12:00:00Z",
"total_pages": 8,
"pages": [
{
"url": "https://example.com",
"title": "Home",
"page_type": "navigation",
"depth": 0,
"links_to": ["https://example.com/about", "https://example.com/contact"]
}
],
"all_forms": [
{
"found_on": "https://example.com/contact",
"id": "contact",
"action": "https://example.com/contact/submit",
"method": "POST",
"fields": [
{ "name": "email", "type": "email", "label": "Your email", "placeholder": "", "required": true, "value": "" },
{ "name": "message", "type": "textarea", "label": "Message", "placeholder": "", "required": true, "value": "" }
]
}
],
"all_navigation": [
{ "label": "About", "url": "https://example.com/about" },
{ "label": "Contact", "url": "https://example.com/contact" }
]
}
invalidate_cache
{ "url": "https://example.com", "invalidated": true }
エラー
ツールが例外をスローすることはありません。失敗した場合:
{
"error": true,
"code": "FETCH_FAILED | PARSE_FAILED | TIMEOUT | NOT_HTML",
"message": "human-readable explanation",
"url": "https://example.com/broken"
}
エージェントによる出力の使用方法
サイトを移動する:
サイトの共通部分(メニュー、ヘッダー、フッター)については navigation を、ページ本文のリンクについては content_links を読み取ります。content_links.total からは、リストが省略されていてもリンクの総数がわかります。目的に合うリンクを選び、interpret_page を呼び出します。
フォームを送信する:
forms を読み取ります。各フィールドには、送信する値を示す name、期待されるデータを示す type、用途を示す label/placeholder、required、および value があります。非表示フィールド(type: "hidden")には CSRF トークンが含まれています。value をそのまま返してください。フラットな name → value 辞書を作成し、submit_form を呼び出します。
確定する前に分類する:
ロジックを分岐させる必要がある場合(たとえば、ログインページかダッシュボードかを判定する場合)は、interpret_page の全処理にかかるコストを避けるため、最初に page_type を呼び出します。
コンポーネントを詳しく調べる:
マップ内で表を見つけたものの、個々の行を確認したい場合や、商品一覧から各カードのリンクと価格を確認したい場合は、CSS セレクターを指定して inspect_element を呼び出します。ページ全体を再読み込みせずに、対象ノードの構造化された詳細を取得できます。
複数ステップのワークフローを事前に計画する:
開始前に site_map を呼び出します。すべてのページのタイトル、種類、深さ、出リンクに加え、サイト内のすべてのフォームを取得できます。これにより、ログインフォーム、データ入力ページ、送信エンドポイントを探すといったワークフロー全体を、リクエストを一度も送信せずに計画できます。
page_type はシグナルであり、保証ではありません:
分類はヒューリスティックです。空の HTML シェルを返す JS レンダリングの SPA は、多くの場合 other になります。パスワードフィールドは、JavaScript が実行されるまで HTML に含まれないためです。page_type は高速なフィルターとして使い、その後、実際の forms と headings を確認してください。
共有レジストリとの同期
デフォルトでは、OSS サーバーが新しく作成したページマップは、Web Speed の共有レジストリ api.getwebspeed.io に非同期で提供されます。これはクラウドソーシングによる好循環です。URL を取得したエージェントがグローバルキャッシュに追加するため、世界中の次のエージェントは即座に応答を得られます。
これはオプトインではなく、オプトアウトです。 貢献者が増えるほど、すべてのエージェントの実行速度が上がるため、デフォルトで有効になっています。
共有される情報
ページの構造データのみです。
- ページの種類、タイトル、説明
- 見出し、ナビゲーションリンク、コンテンツリンク
- フォームフィールドの名前、種類、ラベル(値は含みません)
- 表、テキストブロック
- Open Graph メタデータ
共有されることはありません: Cookie、セッショントークン、フォームの値、JS レンダリングされたマップ(セッション固有のログイン状態が含まれる可能性があります)。
同期を無効にする
サーバーを起動する前に環境変数を設定します。
WEB_SPEED_REGISTRY_SYNC=false python server.py
または、MCP クライアントの設定で指定します。
{
"mcpServers": {
"web-speed": {
"command": "/path/to/venv/bin/python",
"args": ["/path/to/server.py"],
"env": {
"WEB_SPEED_REGISTRY_SYNC": "false"
}
}
}
}
セルフホストのレジストリを指定する
独自のホストインスタンスを実行している場合は、同期先を指定します。
WEB_SPEED_REGISTRY_URL=https://your-instance.example.com python server.py
同期の動作
- ファイア・アンド・フォーゲット:提供データはバックグラウンドで送信されます。ping が成功するかどうかにかかわらず、エージェントのリクエストは通常どおりの速度で完了します。
- キャッシュミス時のみ:ローカルの24時間ディスクキャッシュにすでに存在するマップは再送信されません。
- 失敗は通知されません:ネットワークエラー、タイムアウト、サーバーによる拒否は DEBUG レベルでのみ記録され、エージェントには通知されません。
アーキテクチャ
URL ──▶ fetcher.py (httpx: 10s timeout, 5 redirects, Chrome UA
▼ OR Playwright headless Chromium for js=true)
cleaner.py (BeautifulSoup/lxml: strip noise, split nav vs content
▼ links, filter layout tables, deduplicate text blocks,
structured map infer page_type, detect auth_gated)
▼
cache.py (24h TTL, MD5 keyed JSON files in ./cache/)
▼
registry_sync.py (fire-and-forget POST to api.getwebspeed.io/v1/contribute)
▼
server.py (FastMCP: 8 tools over stdio)
AI はありません。解釈もありません。エージェントが頭脳です。
既知の制限事項
- JavaScript でレンダリングされる SPA:JavaScript(React、Vue、Angular)経由でコンテンツを読み込むページでは、レンダリング前の HTML シェルのみが返されます。JavaScript によって挿入されるパスワード欄、検索結果、ナビゲーションは表示されません。表示されている要素には
inspect_elementを使い、SPA の多い対象ではブラウザー自動化ツールと併用してください。 page_typeのヒューリスティクス:分類は構造に基づいて高速に行われますが、常に正確とは限りません。内部リンクが多いマーケティングページがlistingと判定されたり、メール欄があってもパスワード欄がないページがloginと判定されなかったりすることがあります。- キャッシュはローカルディスク上にあります:
./cache/ディレクトリはローカルです。マルチプロセスまたは分散環境でデプロイする場合、キャッシュエントリーはインスタンス間で共有されません。キャッシュを共有するには、cache.pyを Redis または Memcached のバックエンドに置き換えてください。 - レート制限は適用されません:Web Speed は送信リクエストを制限しません。多数のエージェントを運用する場合は、レート制限プロキシ(Cloudflare、nginx など)をサーバーの前段に配置してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。