CleanPage について
CleanPage は、URL から読みやすい構造化コンテンツを抽出する、エージェント向けの有料 MCP サービスです。Markdown、テキスト、メタデータ、リンク、画像を返し、任意で LLM による事実抽出も行えます。
主な機能
- 01整形済み Markdown とテキストの抽出
- 02メタデータ、リンク、画像の返却
- 03構造化された事実の任意抽出
- 04ヘルス、機能、料金の無料ツール
- 05抽出成功後のみ課金
活用シーン
- 01エージェントによる記事処理の準備
- 02ページ本文とリンクの構造化取得
- 03URL から事実を任意抽出
MCP 対応
Streamable HTTP の MCP エンドポイントで、無料の検出ツールと有料の `clean_page` ツールを提供します。成功した呼び出しは Base 上の x402 により 0.02 USDC で課金され、抽出失敗時は決済されません。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://cleanpage-mcp.cleanpage-mcp.workers.dev/mcpclaude mcp add --transport http io31-web-cleanpage https://cleanpage-mcp.cleanpage-mcp.workers.dev/mcp{"mcpServers":{"io31-web-cleanpage":{"type":"http","url":"https://cleanpage-mcp.cleanpage-mcp.workers.dev/mcp"}}}Cursor で開く{"servers":{"io31-web-cleanpage":{"type":"http","url":"https://cleanpage-mcp.cleanpage-mcp.workers.dev/mcp"}}}VS Code で開く{"mcpServers":{"io31-web-cleanpage":{"type":"http","url":"https://cleanpage-mcp.cleanpage-mcp.workers.dev/mcp"}}}{"mcpServers":{"io31-web-cleanpage":{"serverUrl":"https://cleanpage-mcp.cleanpage-mcp.workers.dev/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
4| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| url | string | はい | 抽出対象ページの絶対URL(http/httpsのみ)。 |
| options | object | いいえ | |
| options.language | string | いいえ | ISO言語ヒント。例:'en'。 |
| options.max_length | integer | いいえ | clean_markdown/plain_textを指定した文字数に切り詰めます。 |
| options.timeout_ms | integer | いいえ | 取得のタイムアウト(ミリ秒、最大20000)。デフォルトは10000です。 |
| options.extract_facts | boolean | いいえ | 構造化された事実/主張の抽出を実行します。遅延が増加しますが、追加料金はかかりません。 |
| options.include_images | boolean | いいえ | 抽出した画像 URL を含めます。デフォルトは true です。 |
詳細
CleanPage
あらゆる URL を、エージェントに最適化された、整理済みのクリーンなコンテンツに変換する有料 MCP ツールです。エージェントは x402 を介して Base 上で、成功した呼び出し 1 回につき $0.02 USDC を支払います。アカウント、API キー、サブスクリプションは不要です。
clean_page(url) → { title, clean_markdown, plain_text, structured_facts,
metadata, links, images, quality_score, extraction_notes }
Cloudflare Workers 向けに構築されています。完全な TypeScript です。ドメインと Base ウォレットアドレス以外に、有料のインフラは必要ありません。
エージェントによる利用方法
-
無料でサービスを確認します。以下はいずれも支払い不要です。
GET /.well-known/agent.json— 機能を機械可読形式で記述したカードGET /.well-known/mcp.json— MCP 接続と料金のマニフェストGET /llms.txt— LLM クローラー向けのプレーンテキストの概要- MCP ツール
health、list_capabilities、pricing(すべて無料)
-
Streamable HTTP を使用して、MCP クライアントを
https://<your-domain>/mcpに接続します。{ "mcpServers": { "cleanpage": { "url": "https://<your-domain>/mcp", "transport": "streamable-http" } } } -
最初は支払いを添付せずに
clean_pageを呼び出します。POST /mcp { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "clean_page", "arguments": { "url": "https://example.com/article" } } }応答は HTTP 402 で、必要な支払いの内容(金額、ネットワーク、アセット、受取人アドレス)を正確に示す
accepts配列が含まれます。 -
署名して再試行します。 要求された金額の USDC
transferWithAuthorization(EIP-3009)支払いペイロードを作成し、Base64 でエンコードして、X-PAYMENTヘッダーを付けて同じリクエストを再試行します。多くの x402 クライアントライブラリ(例:x402-fetch、x402-axios)では、手順 3~4 が自動的に実行されます。 -
結果を取得します。 成功すると、応答には完全な JSON 結果と、決済トランザクションのハッシュを含む
X-PAYMENT-RESPONSEヘッダーが含まれます。抽出に失敗した場合(ペイウォール、ボットによるブロック、空のページ)は、料金が請求されることはありません。決済は抽出の成功後にのみ行われます。
プロトコルの詳細については、デプロイ後に /llms.txt と /.well-known/mcp.json を参照するか、ランディングページの「エージェント向け」セクションを参照してください。
プロジェクト構成
cleanpage/
├── src/
│ ├── index.ts # Hono app: routes, x402 payment gate, static asset fallback
│ ├── types.ts # Shared types (Env, CleanPageResult, etc.)
│ ├── config.ts # Reads env vars into a typed config object
│ ├── mcp/
│ │ ├── server.ts # JSON-RPC 2.0 / MCP method dispatcher (stateless)
│ │ └── tools.ts # Tool schemas + descriptions (clean_page, health, ...)
│ ├── extraction/
│ │ ├── extractor.ts # Core pipeline: fetch → Readability → markdown/links/metadata
│ │ └── enrichment.ts # Optional cheap LLM pass for structured_facts
│ ├── payments/
│ │ └── x402.ts # x402 payment requirements, facilitator verify/settle
│ └── middleware/
│ └── limits.ts # KV-backed rate limiting + call/revenue analytics
├── public/ # Static assets served at the Worker's root
│ ├── index.html # Landing page (live demo, pricing, docs, for-agents)
│ ├── robots.txt # Explicitly welcomes agent/LLM crawlers
│ ├── llms.txt # Plain-text agent-facing summary
│ └── .well-known/
│ ├── agent.json # Agent discovery/capability card
│ └── mcp.json # MCP connection + pricing manifest
├── wrangler.toml # Cloudflare Workers config (bindings, vars)
├── package.json
├── tsconfig.json
└── .env.example # Documents every config value
アーキテクチャに関するメモ
MCP トランスポート。 MCP Streamable HTTP トランスポートは、公式 SDK の Node 向け HTTP トランスポートクラスを介さず、src/mcp/server.ts でステートレスな JSON-RPC 2.0 ディスパッチャー(initialize、tools/list、tools/call、ping)として直接実装されています。これは Cloudflare Workers 上で正しく動作させるための意図的な選択です。SDK のトランスポートは Node の http.IncomingMessage/ServerResponse を対象としていますが、Workers にはこれらがありません。このディスパッチャーは同じワイヤープロトコル(単一の POST エンドポイント上の JSON-RPC、リクエストごとにサーバー単位のセッションを 1 つ使用)に従うため、標準的な MCP クライアントであれば接続できます。後で Node ベースのホスト上で実行する場合は、@modelcontextprotocol/sdk の StreamableHTTPServerTransport に直接置き換えられます。
決済ゲーティング。 POST /mcp は解析済みの JSON-RPC ボディを確認し、clean_page を指定した tools/call リクエストのみを決済ゲーティングの対象にします(src/index.ts)。health、list_capabilities、pricing、およびツール呼び出し以外のすべてのメソッド(initialize、tools/list など)は、そのまま処理されます。レート制限は適用されますが、料金はかかりません。これにより、エージェントが利用できる検出機能はすべて開放し、有料機能のうち 1 つだけをゲーティングできます。
決済確定のタイミング。 決済は抽出の実行前に検証されますが、オンチェーンでの確定(ブロードキャスト)は抽出が成功した後にのみ行われます。抽出に失敗した場合、エージェントの決済承認は破棄され、請求は発生しません。
秘密鍵は不要です。 Base 上の USDC は EIP-3009 メタトランザクションに対応しているため、リソースサーバーが秘密鍵を保持することはありません。PAYMENT_ADDRESS は公開ウォレットアドレスです。ファシリテーターが署名済みの承認をオンチェーンで送信し、ガス代を負担します。
抽出エンジン。 Firefox のリーダーモードの基盤となっている @mozilla/readability が、コンテンツ抽出の中核を担います。抽出は linkedom(Workers で動作する高速かつ依存関係の少ない DOM 実装。jsdom は動作しません)で構築された DOM に対して実行されます。Workers に対応し、かつ DOM ベースでもある既存の Markdown 変換ライブラリがないため、抽出されたフラグメントを Markdown に変換する処理には、小規模な手書きの HTML→Markdown ウォーカーを使用しています。抽出前後のヒューリスティックにより、よくある失敗要因であるペイウォールのマーカー、ボットチェックのページ、JavaScript のみで構成された空のページを検出し、品質の低い出力ではなく型付きエラーを返します。
任意の LLM による拡張。 structured_facts が設定されるのは、呼び出し元が options.extract_facts: true を渡し、かつ ENABLE_LLM_ENRICHMENT=true と ANTHROPIC_API_KEY が設定されている場合のみです。これはクリティカルパスには含まれません。拡張処理の呼び出しが失敗した場合や無効になっている場合でも、clean_page は structured_facts が空の配列である完全な結果を返し、理由を説明する注記を付けます。この機能の使用に追加料金はかかりません。
レート制限と分析。 どちらも 1 つの KV 名前空間で実装されています。無料プランの呼び出しにはクライアント IP ごとの固定 1 分間カウンターを使用し、呼び出し数/成功数/失敗数/収益については累積 JSON カウンターオブジェクトを使用します。これらの情報は GET /analytics で読み取り専用として公開されます。
必要なサービス/インフラストラクチャ
| コンポーネント | 必要なもの | 入手先 |
|---|---|---|
| ホスティング | Cloudflare Workers(Static Assets 対応) | dash.cloudflare.com — まずは無料プランで利用できます |
| ドメイン+DNS | Cloudflare 経由でプロキシされるドメイン | 任意のレジストラーで取得し、Cloudflare に追加して Worker に向けます |
| ウォレット | Base ウォレットアドレス(公開アドレスのみ) | 任意の EVM ウォレット — Coinbase Wallet、MetaMask など |
| x402 ファシリテーター | 決済の検証/確定 | https://x402.org/facilitator(テストネット向けのデフォルト)。メインネットでの本番運用には、Coinbase が運営するファシリテーター、またはセルフホストのファシリテーターを使用します |
| KV 名前空間 | レート制限+分析データの保存 | wrangler kv namespace create CLEANPAGE_KV |
| LLM(任意) | 構造化された事実の抽出 | Anthropic API キー。ENABLE_LLM_ENRICHMENT=true の場合のみ必要 |
データベースもキューも別のバックエンドも不要です。すべて 1 つの Worker で実行されます。
デプロイ(手順)
# 1. Install dependencies
npm install
# 2. Create the KV namespace used for rate limiting + analytics
npx wrangler kv namespace create CLEANPAGE_KV
npx wrangler kv namespace create CLEANPAGE_KV --preview
# Copy the two returned IDs into wrangler.toml under [[kv_namespaces]]
# 3. Edit wrangler.toml [vars]:
# - PAYMENT_ADDRESS → your Base wallet address
# - PUBLIC_BASE_URL → your real domain, e.g. https://cleanpage.yourdomain.com
# - X402_NETWORK → "base-sepolia" while testing, "base" for mainnet
# Also update the same URLs/addresses in:
# - public/.well-known/agent.json
# - public/.well-known/mcp.json
# - public/llms.txt
# - public/index.html (og:url, structured data, MCP config example)
# 4. (Optional) enable LLM fact extraction
npx wrangler secret put ANTHROPIC_API_KEY
# 5. Type-check
npm run typecheck
# 6. Deploy
npm run deploy
# 7. Point your domain at the Worker (Cloudflare dashboard → Workers →
# your worker → Triggers → Custom Domains), or use the workers.dev
# subdomain Wrangler prints after deploy.
ローカル開発
npm run dev
# Worker runs at http://localhost:8787
# Try: curl -X POST http://localhost:8787/mcp -H "Content-Type: application/json" \
# -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
テストネットからメインネットへの移行
wrangler.tomlでX402_NETWORKをbase-sepoliaからbaseに切り替えます。X402_FACILITATOR_URLをメインネットに対応したファシリテーターに切り替えます(選択したファシリテーターがBaseメインネットでの決済に対応していることを確認してください。このエコシステムはまだ発展途上で、選択肢は変化するため、現在のファシリテーターの選択肢を確認してください)。- 再デプロイします。
環境変数
注釈付きの一覧については.env.exampleを参照してください。概要:
| 変数 | 必須 | デフォルト | 用途 |
|---|---|---|---|
PAYMENT_ADDRESS | はい | — | USDCを受け取るBaseウォレットアドレス |
X402_NETWORK | はい | base-sepolia | baseまたはbase-sepolia |
X402_FACILITATOR_URL | はい | https://x402.org/facilitator | 検証/決済に使用するファシリテーター |
CLEAN_PAGE_PRICE_USD | はい | 0.02 | clean_page呼び出しが成功した場合の料金 |
PUBLIC_BASE_URL | はい | — | デプロイ済みのURL。ディスカバリーファイルで使用します |
FREE_RATE_LIMIT_PER_MIN | いいえ | 30 | IPごとの無料枠の1分あたりの呼び出し数 |
ENABLE_LLM_ENRICHMENT | いいえ | true | structured_factsの抽出を有効にします |
LLM_MODEL | いいえ | claude-haiku-4-5-20251001 | 情報補完に使用するモデル |
ANTHROPIC_API_KEY | 情報補完を有効にする場合のみ | — | シークレット。wrangler secret putで設定します |
MCP クライアント設定の例
{
"mcpServers": {
"cleanpage": {
"url": "https://cleanpage.yourdomain.com/mcp",
"transport": "streamable-http"
}
}
}
ツール呼び出しとレスポンス形式の例
リクエスト:
{
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "clean_page",
"arguments": { "url": "https://example.com/article", "options": { "extract_facts": true } }
}
}
成功レスポンス(決済後)— result.content[0].textは、次の形式のJSON文字列です:
{
"title": "Article title",
"clean_markdown": "# Article title\n\nBody content as markdown…",
"plain_text": "Body content as plain text…",
"structured_facts": [
{ "claim": "…", "category": "fact", "confidence": 0.82 }
],
"metadata": {
"author": "Jane Doe", "published_date": "2026-08-01T00:00:00Z",
"site_name": "Example", "language": "en",
"word_count": 812, "reading_time_minutes": 4,
"fetched_at": "2026-09-17T12:00:00.000Z",
"final_url": "https://example.com/article", "status_code": 200
},
"links": [{ "url": "https://example.com/other", "text": "related", "type": "internal" }],
"images": ["https://example.com/hero.jpg"],
"quality_score": 85,
"extraction_notes": []
}
エラーコード
error_code | 意味 | 再試行可能 |
|---|---|---|
INVALID_URL | 形式が不正、http(s)ではない、またはブロック対象の内部アドレスです | いいえ |
FETCH_FAILED | 2xx以外のレスポンス、HTML以外のコンテンツ、またはサイズ超過のページです | 場合によります |
TIMEOUT | タイムアウト時間内にページから応答がありませんでした | はい |
PAYWALL_DETECTED | サブスクリプション制または従量制のペイウォールが検出されました | いいえ |
BLOCKED_BY_SITE | ボットチェック/CAPTCHA、またはJavaScriptのみで表示される空のシェルです | いいえ |
EMPTY_CONTENT | 実質的な記事コンテンツが見つかりませんでした | いいえ |
EXTRACTION_FAILED | 予期しないパーサーエラーです | いいえ |
抽出に失敗した場合は、必ず決済処理の前に返されるため、料金が請求されることはありません。
既知の制限事項
- JavaScriptで描画されるページ:抽出では生のHTMLを取得し、JavaScriptは実行しません。そのため、サーバー側で描画されたコンテンツがない、クライアント側で描画されるSPAは、
EMPTY_CONTENTまたはBLOCKED_BY_SITEを返します。トラフィックへの影響がある場合、ヘッドレスブラウザーによる描画のフォールバック(Cloudflare Browser Renderingなど)を追加するのが自然な次のステップです。 - ファシリテーターへの依存:決済の検証と決済処理は、設定されたx402ファシリテーターの稼働状況に依存します。開発環境では
x402.org/facilitatorが適したデフォルトですが、メインネットの利用量を増やす前に、本番環境向けファシリテーターの信頼性保証を評価してください。 - レート制限はベストエフォートです:KVベースのカウンターには、同じIPから同時に大量のリクエストが発生した場合に、小さな競合ウィンドウがあります。これは十分な不正利用対策ですが、確実な保証ではありません。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。