mcpField
B
Bintu Web Reader

Bintu Web Reader

リモート
github.com/l20941485-blipブラウザ自動化0今日更新
リポジトリ

Bintu Web Reader について

Bintu Web Readerは、公開HTMLページからAIエージェント向けの読みやすいテキストを抽出するAPIです。ページ構造をMarkdown形式に整え、MCPツールとHTTPエンドポイントを提供します。

主な機能

  1. 01HTMLから読みやすいテキストを抽出
  2. 02見出しと表をMarkdown形式で表現
  3. 03JavaScriptページの任意レンダリング
  4. 04テキスト上限と切り詰めフラグ
  5. 05公開URLと応答サイズの検証
  6. 06短時間の抽出キャッシュ

活用シーン

  1. 01エージェント向けに公開ページのテキストを抽出
  2. 02有効化時にJavaScriptページを読み取り
  3. 03テキスト予算内で抽出内容を確認

MCP 対応

ステートレスなStreamable HTTP MCPエンドポイントで、bintu_scrape_textツールを公開します。MCPツール呼び出しにはスクレイプAPIと同じ認証とレート制限が適用されます。

設定

リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。

エンドポイントhttps://bintu-web-reader.mcpize.run/mcp
インストールコマンドをコピー
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。

すべてのエンドポイント
Streamable HTTPhttps://bintu-web-reader.mcpize.run/mcp認証が必要

ツール

詳細

Bintu Data Extraction API

Bintu は、公開 HTML ページから読み取り可能なテキストを抽出する、FastAPI ベースの API です。上流レスポンスを 1 MiB に制限し、HTML/XHTML のみを受け付け、送信先への接続を検証済みのパブリック IP に固定し、プロセス内で毎分 60 リクエストのバースト制限を適用します。

ライブ API

サービスは Render で稼働中で、テストできます。

ヘルスチェック
curl https://bintu-api.onrender.com/healthz

レスポンス例:

{
  "status": "ok"
}
テキストのスクレイピング

デプロイ済みサービスに直接アクセスするには、PowerShell で API キーを設定します。セキュリティで保護されたプロンプトを使うと、入力中にキーが画面に表示されません。

$env:BINTU_BASE_URL = "https://bintu-api.onrender.com"
$secure = Read-Host "Paste your Render API_KEY" -AsSecureString
$env:BINTU_API_KEY = [System.Net.NetworkCredential]::new("", $secure).Password
Remove-Variable secure

認証付きのスクレイピングリクエストを送信します。

$target = "https://www.iana.org/domains/reserved"
$encodedUrl = [uri]::EscapeDataString($target)
$headers = @{ "X-API-Key" = $env:BINTU_API_KEY }

try {
    $result = Invoke-RestMethod `
        -Uri "$env:BINTU_BASE_URL/api/v1/scrape/text?url=$encodedUrl" `
        -Headers $headers
    $result | ConvertTo-Json -Depth 5
}
catch {
    $response = $_.Exception.Response
    if ($response) {
        $statusCode = [int]$response.StatusCode
        $retryAfter = $response.Headers["Retry-After"]
        Write-Host "HTTP $statusCode; Retry-After: $retryAfter"
        $reader = [System.IO.StreamReader]::new($response.GetResponseStream())
        try { $reader.ReadToEnd() } finally { $reader.Dispose() }
    }
    else {
        throw
    }
}

成功時のレスポンス:

{
  "url": "https://www.iana.org/domains/reserved",
  "text": "# IANA-managed Reserved Domains\n## Example domains\n...",
  "truncated": false
}

抽出したテキストが設定された文字数制限を超えた場合、truncated は true になります。API はリクエストされた URL を url で返します。

PowerShell で curl.exe を使う場合も、同じリクエストを次のように送信できます。

curl.exe --get "$env:BINTU_BASE_URL/api/v1/scrape/text" `
  --data-urlencode "url=https://www.iana.org/domains/reserved" `
  --header "X-API-Key: $env:BINTU_API_KEY" `
  --header "Accept: application/json"

Render の API_KEY は、サービスの Environment 設定で確認できます。キーは非公開にし、コミットしたり URL に含めたりしないでください。上記の例では、現在の PowerShell プロセスの環境変数にキーを保持しています。API キーもプロキシシークレットも設定されていない場合(デフォルトのローカル開発環境など)、認証は不要です。インタラクティブな API ドキュメントは /docs で利用できます。右上の Authorize をクリックして、ApiKeyAuth にキーを、モバイルエンドポイントでは BearerAuth に Supabase セッショントークンを貼り付けてから、認証が必要な任意のルートで Try it out を使用します。

よくあるエラー

エラーは、code、message、該当する場合は hint を含む JSON の detail オブジェクトを使用します。たとえば、キーがないか無効な場合は HTTP 401 が返されます。

{
  "detail": {
    "code": "invalid_api_key",
    "message": "A valid API key is required."
  }
}

URL が無効または安全でない場合は HTTP 400 が返されます。

{
  "detail": {
    "code": "invalid_or_unsafe_url",
    "message": "URL must be an absolute HTTP or HTTPS URL",
    "hint": "URL must start with http:// or https:// and be publicly accessible"
  }
}
HTTP ステータスエラーコード対処方法
400invalid_or_unsafe_url, render_js_disabled形式が正しいパブリック HTTP または HTTPS の URL を使用してください。プライベートネットワーク宛ての接続はブロックされます。サービスで有効化されていない限り、render_js=true は無効です。render_js=false にして再試行してください。
401invalid_api_keyRender で設定されている現在の X-API-Key を送信してください。
500auth_misconfigurationREQUIRE_AUTH=true(Render の本番環境でのデフォルト)が設定されていますが、API_KEY と RAPIDAPI_PROXY_SECRET がどちらも空です。Render ダッシュボードでシークレットを復元し、再デプロイしてください。
413payload_too_largeHTML の展開後のサイズが 1 MiB を超えています。
415unsupported_media_type対象は HTML または XHTML を返す必要があります。
429burst_rate_limit_exceededRetry-After レスポンスヘッダーで指定された秒数だけ待ってから再試行してください。
502upstream_http_error, upstream_connection_error, upstream_render_error, unsupported_content_encoding, too_many_redirects対象がエラーを返した、接続またはレンダリングができなかった、サポートされていない圧縮方式が使われた、またはリダイレクトが多すぎました。
504upstream_timeout対象が時間内に応答しませんでした。

429 レスポンスには Retry-After ヘッダーも含まれます。4xx レスポンスに対する再試行を繰り返さないでください。リクエストを修正するか、指定された時間だけ待ってください。

ローカルで実行する

Python 3.12 を使用してください。アプリケーションとテストの依存関係をインストールしてから、サービスを起動します。

python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements-dev.txt
cd "Bintu API"
uvicorn main:app --reload

インタラクティブな API ドキュメントは /docs にあります。キーが設定されていない場合、ローカル開発環境は認証なしで利用できます。保護されていないインスタンスをデプロイしないでください。Render のブループリントでは、デフォルトで API_KEY が生成されます。

Docker
docker build -t bintu-api .
docker run -p 8000:8000 -e API_KEY=your-key bintu-api

または、Docker Compose を使用します。

docker-compose up

API

GET /healthz は、Render の軽量なヘルスチェックです。認証は不要です。

GET /version は、サービスの設定を返します(シークレットは公開されません)。

GET /metrics は、Prometheus のリクエスト数、エラー数、レイテンシーヒストグラム、キャッシュのヒット数/ミス数を公開します。メトリクスではリクエスト URL ではなくルートテンプレートを使用し、取得したコンテンツは含めません。アプリケーションのリクエストログには、リクエスト ID、メソッド、ルートテンプレート、ステータス、所要時間が記録されます。対象 URL やページのテキストは記録されません。アクセスログのリクエスト行には url クエリパラメーターが含まれる場合があるため、Render と Docker の起動設定では Uvicorn のアクセスログを無効にしています。このエンドポイントは API と同じ認証情報で保護されるため、キーが設定されている場合は X-API-Key(または RapidAPI プロキシのヘッダー)を送信してください。すべてのレスポンスで X-Request-ID が返されます。有効な ID が呼び出し元から指定された場合はそれを保持し、そうでない場合は API が生成します。

GET /api/v1/scrape/text?url=https%3A%2F%2Fexample.com は、指定された URL、抽出されたテキスト、truncated ブール値を返します。truncated が true になるのは、抽出されたコンテンツが設定済みのテキスト上限を超えた場合のみです。抽出時は、利用可能であれば <article> または <main> のコンテンツを優先し、次に role="main" または一般的な名前の main/content コンテナー(id="main" など)を使用し、それ以外の場合はドキュメント全体を対象とします。非表示要素や、一般的なコントロール類・ページの装飾要素は除外し、リンクは リンクテキスト (絶対 URL) の形式で出力します。見出しには Markdown の # 接頭辞を付け、段落やその他のブロック要素は改行で区切ります。各行のテーブルセルは | で結合し、ヘッダー行の下には区切り線を挿入します。ドキュメントタイトルが最初の見出しと重複する場合、タイトルは省略されます。文字コードは、上流 HTTP の charset と HTML メタデータから検出します。直接呼び出す場合、API_KEY が設定されていれば X-API-Key を送信する必要があります。このエンドポイントがサポートするのは、パブリックな HTTP/HTTPS 接続先のみであり、アクセス制御を回避することはありません。

JavaScript で動作するページを対象にするには、render_js=true を追加してヘッドレス Chromium によるレンダリングを有効にします。レンダリングでは networkidle を待機し、ブラウザーがリクエストする HTTP 接続先について、DNS 解決結果がパブリック IP アドレスであることを検証します。また、メモリ使用量を抑えるため、画像、メディア、フォントを除外します。レンダリングしないリクエストでは、接続ごとに検証済みのパブリック IP に固定する既存の軽量トランスポートが引き続き使用されます。どちらのモードでも、同じ抽出処理、テキスト上限、永続キャッシュ、認証、レート制限が適用されます。

POST /mcp は、Claude カスタムコネクターおよび Claude Code 向けの標準的な MCP Streamable HTTP エンドポイント(ステートレス JSON-RPC 2.0)です。単一の bintu_scrape_text ツールについて、initialize、ping、tools/list、tools/call に応答します。また、Content-Type: application/json と通常のリクエストと同じ API キーが必要です。Claude カスタムコネクターの接続先を https://<your-host>/mcp に設定し、リクエストヘッダーとして X-API-Key を指定してください。通知には 202 を返します。サーバーはセッションやストリームを保持しないため、GET/DELETE には 405 を返します。

GET /mcp/tools は bintu_scrape_text ツールを公開し、POST /mcp/tools/call は {"name":"bintu_scrape_text","arguments":{"url":"https://example.com","render_js":false}} でツールを呼び出します。レスポンスは MCP のツールコンテンツ形式に従います:{"content":[{"type":"text","text":"..."}]}。ツールの呼び出しには、通常のスクレイピングリクエストと同じ API 認証とレート制限が適用されます。

クエリパラメーター
パラメーター型デフォルト説明
urlstring必須スクレイピングする URL
render_jsboolfalse抽出前にヘッドレス Chromium で JavaScript をレンダリングします
include_navboolfalse出力に <nav> 要素を保持します
include_headerboolfalse出力に <header> 要素を保持します
include_footerboolfalse出力に <footer> 要素を保持します
サービス制限
  • リクエストのタイムアウト:接続試行ごとに10秒です。
  • リダイレクト:最大5回です。遷移先ごとにURLとDNSの検証を繰り返します。
  • HTML本文:展開後で最大1 MiBです。4 KiB以下のチャンク単位で読み込みます。Gzip圧縮されたHTMLも、展開後のサイズ制限は同じです。
  • テキストレスポンス:最大6,000文字です。コンテンツが上限を超えると、truncated は true になります。テキストは、取得可能な最後の単語の境界で切り詰められます。
  • JavaScriptのレンダリング:デフォルトでは無効です(RENDER_JS_ENABLED=false)。render_js=true を指定すると、400 render_js_disabled が返されます。Chromiumの起動コストを負担できる有料インフラでのみ有効にしてください。
  • ローカルの不正利用防止機能:クライアントIDごとに60秒あたり60リクエストまでです。プロセスメモリ内でのみ動作します。Renderの背後では、クライアントIPはRenderのプロキシ範囲(100.64.0.0/10)からのものだけが使用されるため、X-Forwarded-For の偽装による回避はできません。インスタンス間でカウンターを共有するには REDIS_URL を設定してください。ウィンドウのTTLはウィンドウごとに一度だけ設定されます。Redisに接続できない場合、リクエストを失敗させず、プロセスメモリにフォールバックします。
  • プロセス内HTMLキャッシュ:TTLは5分で、インスタンスあたり最大64件を保持し、最も古く使われた項目から削除します。CACHE_TTL_SECONDS=0 にすると、このローカルキャッシュは無効になります。設定されている場合、別個のSupabase Markdownキャッシュは、抽出に成功した内容を24時間保持します。
  • 有料サブスクリプションのクォータと課金:本サービスではなく、RapidAPIで設定および適用されます。

設定

環境変数デフォルト値説明
API_KEY(空)直接アクセス用のAPIキー
RAPIDAPI_PROXY_SECRET(空)RapidAPIプロキシ認証用のシークレット
SUPABASE_URL(空)モバイルユーザーのセッション検証に使用するSupabaseプロジェクトURL
SUPABASE_ANON_KEY(空)モバイルセッションの検証に使用するSupabaseの公開可能なanonキー。サービスロール/シークレットキーは絶対に使用しないでください
SUPABASE_SERVICE_ROLE_KEY(空)永続的なスクレイピングキャッシュとRapidAPIの使用量記録に使用する、サーバー側の非公開キー
CACHE_TTL_SECONDS300プロセス内HTMLキャッシュのTTL(秒)。0 にするとそのキャッシュは無効になります(Supabaseの24時間キャッシュとは別です)。数値以外の値、または範囲外の値(許容範囲は0~86400)は、ログに警告を記録して300にフォールバックします
REDIS_URL(空)複数インスタンスでのレート制限に使用するRedis URL。空または接続不可の場合は、プロセスごとのバースト制限(フェイルオープン)となり、各インスタンスが独自のウィンドウを適用します
RENDER_JS_ENABLEDfalseJavaScriptレンダリングのキルスイッチ。値が厳密に true の場合のみChromiumが有効になります。それ以外の場合、render_js=true に対して400 render_js_disabled が返されます
BINTU_UPGRADE_URLhttps://mcpize.comMCP 401 -32001 の upgrade_url に埋め込まれる正規の登録URLです。エージェントがチャット内にクリック可能なリンクを表示します

Renderへのデプロイ

  1. このプロジェクトをGitHubリポジトリにプッシュします。
  2. Renderで新しいBlueprintを作成し、そのリポジトリを選択します。Renderは render.yaml を読み込み、requirements.txt とChromiumのシステム依存関係をインストールした後、割り当てられたポートでUvicornを起動します。
  3. /healthz が正常になるまで待ちます。直接APIにアクセスする場合は、サービス環境から生成された API_KEY をコピーします。どちらのシークレットもコミットしないでください。
  4. 公開する前に、デプロイ済みの /docs ページをテストし、認証済みのスクレイピングリクエストを実行します。

無料インスタンスはアイドル状態の間にスリープすることがあるため、最初のリクエストは遅くなる場合があります。無料サービスは検証や初期ユーザー向けであり、レイテンシに厳しい本番環境や稼働時間の保証には適していません。ローカルのバースト制限は再起動時にリセットされ、インスタンス間で共有されません。有料クォータではないため、課金の基準としてRapidAPIのプラン制限を使用してください。

ストアフロントの同等性(単一の信頼できる情報源)

1 つの API、3 つの窓口です。動作は同一で、異なるのはゲートウェイごとの認証と課金のみです。

Direct(Render)RapidAPIMCPize
掲載名サービス bintu-data-extraction-api(MCP serverInfo.name: bintu)Bintu Data Extraction API(サブドメイン bintu-data-extraction-api)LLM Web Scraper & Clean Text Extractor(スラッグ/ホスト bintu-web-reader.mcpize.run。ユーザーは Claude コネクターに Bintu-web-reader というラベルを付けます)
エンドポイントhttps://bintu-api.onrender.com の GET /api/v1/scrape/text?url=…https://bintu-data-extraction-api.p.rapidapi.com の同じパスhttps://bintu-web-reader.mcpize.run の bintu_scrape_text ツール(上流は POST https://bintu-api.onrender.com/mcp)
認証X-API-Key: <Render API_KEY>X-RapidAPI-Key + X-RapidAPI-Host(ゲートウェイが X-RapidAPI-Proxy-Secret + X-RapidAPI-User を挿入)サブスクライバーの MCPize キー(sk_…)。ゲートウェイが上流の X-API-Key を挿入します。MCPize のページから購入者を RapidAPI に誘導しないでください
課金なし(所有者キー)RapidAPI のプラン:BASIC $0/100 · PRO $9/10k · ULTRA $29/50k · MEGA $79/100k+MCPize のパブリッシャー向けプラン(ダッシュボード → 収益化):Free ~1k · Pro $9–19 · Team $49+(Stripe Connect 経由で 80%)
クォータIP ごとに 60 秒あたり 60 リクエストのバースト制限X-RapidAPI-User ごとに 60 秒あたり 60 リクエスト + プランのクォータMCPize のサブスクライバー全体で 60 秒あたり 60 リクエスト(上流トークンは 1 つ)+ プランのクォータ
キャッシュメモリ内で 5 分 + Supabase に 24 時間永続化同左同じ上流キャッシュ。コールドフェッチは約 2~6 秒、キャッシュヒットは約 300 ミリ秒

トークン課金対策の位置付け(MCP): bintu_scrape_text は、トークンをサニタイズするコンテキストゲートウェイです。ナビゲーション/広告/フッターを除去し、決定的な max_tokens チャンクを生成します(chunked→chunk、chunk_token_budget→max_tokens のエイリアス)。すべてのモードで、統一された JSON エンベロープ {mode, tokens, chunk_count, cache_hit, source_url, extracted_at, tokens_saved_estimate, truncated, chunks} を content[0].text に返し、X-Token-Usage ヘッダーと 401 -32001 の upgrade_url(https://mcpize.com、BINTU_UPGRADE_URL で上書き可能)も返します。コードにプランごとの上限はありません。クォータはダッシュボードで管理します。新しい環境変数:BINTU_UPGRADE_URL(デフォルトは https://mcpize.com)。

すべての環境に適用される制限:上流の本文は 1 MiB、HTML/XHTML のみ、テキスト上限は 6,000 文字(truncated フラグ付き)、リダイレクトは 5 回まで、render_js=true は 400 render_js_disabled を返します(有料インフラで RENDER_JS_ENABLED=true にするまではプレーン HTML のみ)。エラーコードについては、共通エラーを参照してください。

RapidAPI への公開

RapidAPI はゲートウェイでサブスクライバーの認証と課金を処理します。RapidAPI のプロバイダーダッシュボードで、API のベース URL を Render サービスに設定し、プロキシシークレットを構成してください。Render の RAPIDAPI_PROXY_SECRET に同じ値を設定します。X-RapidAPI-Proxy-Secret で認証されたリクエストを受け付けます。X-RapidAPI-User の ID ごとに、独立した 1 分あたり 60 リクエストの枠が適用されます。所有者または直接アクセス用に API_KEY を保持し、クライアント向けの例ではどちらのシークレットも公開しないでください。

RapidAPI でサブスクリプションプラン、月間クォータ、料金を設定してください。まずは少額の無料トライアルと、Render のレイテンシ、障害率、上流コストの実測値に基づいた有料プランから始めましょう。サービスの 1 分あたり 60 リクエストという制限はバースト制限であり、月間クォータや課金システムではありません。マーケットプレイスでの掲載順位や収益は保証されません。

アクセス権限のあるコンテンツのみをスクレイピングしてください。対象サイトの利用規約と robots ポリシーを遵守してください。この API は、ログイン、CAPTCHA、ペイウォール、ボット対策を回避しません。

Claude に接続する

POST /mcp は標準の MCP Streamable HTTP トランスポート(プロトコル 2025-11-25。2025-06-18/2025-03-26 も受け付けます)を実装しているため、あらゆる MCP クライアントからスクレイパーを呼び出せます。ステートレスで、Mcp-Session-Id は発行されません。GET は空の SSE ストリームを返し(専用の SSE パスを確認するゲートウェイ向けに、GET /sse と GET /mcp/sse も互換性エイリアスとして用意されています)、DELETE/PUT/PATCH は 405 を返します。また、各 JSON-RPC メッセージには単一の application/json レスポンスを返します。initialize の後のリクエストには、ネゴシエート済みの MCP-Protocol-Version ヘッダーが必要です(不明なバージョンには 400 を返します)。DNS リバインディング対策として、一致しない Origin ヘッダーは 403 で拒否されます。initialize、tools/list、ping は公開されている検出用メソッドです(プロトコルのネゴシエーション、ツールのスキーマ、稼働確認を行い、抽出は行いません)。そのため、オンボーディング中にヘッダーを送信できないゲートウェイのヘルスチェッカー、マーケットプレイスの監査機能、Claude Web はすぐに処理を完了できます。tools/call およびその他すべてのメソッドには、スコープ付きの MCP_API_KEY またはマスター API_KEY を使用した X-API-Key か Authorization: Bearer が必要です。実行呼び出しに認証情報がない、または無効な場合は、{"code": "invalid_api_key", "message": "A premium subscription or valid X-API-Key is required to execute scrapes."} を含む 401 を返します。課金対象の処理はすべて認証の背後で実行されます。

  • 直接接続 — Claude Web または Desktop:カスタムコネクターの URL https://bintu-api.onrender.com/mcp に、リクエストヘッダー X-API-Key: <MCP_API_KEY> を設定します。
  • 直接接続 — Claude Code:claude mcp add --transport http bintu https://bintu-api.onrender.com/mcp --header "X-API-Key: <MCP_API_KEY>"。
  • MCPize(サブスクライバー):MCPize の sk_… キーを使って https://bintu-web-reader.mcpize.run に接続します。ゲートウェイが上流のトークンを挿入します。RapidAPI のサブスクリプションは不要です。課金は MCPize の掲載ページで行われます。

MCP_API_KEY は Render ダッシュボードで設定するオプションのスコープ付きキーです。MCP のエンドポイント(/mcp、/mcp/tools、/mcp/tools/call)でのみ受け付けられ、REST ルートや /metrics では使用できません。そのため、コネクターのユーザーと共有でき、マスター API_KEY に触れることなくローテーションできます。MCP_API_KEY が未設定の場合も、これまでどおりマスター API_KEY を /mcp で使用できます。

サーバーは、REST のスクレイプと同じスキーマを持つ bintu_scrape_text というツールを1つ公開します。ツールの実行に失敗した場合(安全でない URL、レート制限、上流エラー、render_js_disabled)、モデルが自ら修正できるよう、読み取り可能なテキストとともに isError: true をインバンドで返します。実行リクエスト(tools/call)には有効なキー(X-API-Key または Authorization: Bearer 経由のマスター API_KEY またはスコープ付き MCP_API_KEY)が必要で、同じレート制限の対象となります。検出(initialize、tools/list、ping)には認証情報は不要です。このエンドポイントは /docs には表示されません。README の MCP セクションを参照してください。

ネイティブモバイル MVP

mobile-app/ の Expo プロジェクトでは、iOS および Android 向けにメールでのサインアップ/サインイン機能と、URL を読みやすいテキストに変換する画面を提供します。ユーザーセッションはデバイスのセキュアストレージに保存されます。アプリは Supabase のアクセストークンを POST /api/v1/mobile/scrape/text に送信します。API は Supabase でユーザーを検証し、メールアドレスが認証済みであることを要求して、既存のユーザーごとのバースト制限を適用します。Bintu の API_KEY と RapidAPI プロバイダーのシークレットがアプリに送信されることはありません。

バックエンドを設定する
  1. Supabase プロジェクトを作成し、メール/パスワード認証を有効にします。メール確認は有効のままにしてください。
  2. Supabase プロジェクトの設定で、プロジェクト URL と公開可能キー(または従来の anon キー)をコピーします。service_role キーやシークレットキーは使用しないでください。
  3. Render サービスの環境変数に SUPABASE_URL と SUPABASE_ANON_KEY を設定します。既存の生成済み API_KEY は非公開のままにしてください。
  4. 永続的なスクレイピングキャッシュと RapidAPI の使用回数を有効にするには、サーバー専用の SUPABASE_SERVICE_ROLE_KEY を Render に設定します。Supabase の SQL エディターで supabase_schema.sql を実行し、必要なテーブルとアトミックな使用回数加算関数を作成します。サービスロールキーをモバイルアプリに含めないでください。このキーを設定しない場合、スクレイピングは既存の上限付きインメモリーキャッシュを使用して続行され、データベース機能は無効になります。

永続キャッシュは、成功した Markdown を 24 時間保持します。キャッシュキーには URL、レンダリングモード、抽出オプションが含まれ、有効期限が切れたエントリーは無視されます。RapidAPI の使用回数は、有効な設定済み RapidAPI プロキシシークレットと有効な X-RapidAPI-User ヘッダーを含むリクエストに対してのみ加算されます。成功したキャッシュ呼び出しもカウントされます。データベースのエラーはログに記録され、スクレイピングにフォールバックするか、正常に抽出されたコンテンツを返します。

Supabase の設定が両方とも構成されるまで、モバイルプロキシは利用できません。API が各セッションを検証できるよう、リクエスト時に Supabase に接続できる必要があります。

Supabase の Authentication → URL Configuration → Redirect URLs で、Expo Go のコールバック exp://**/--/auth/callback と、インストール済みアプリのコールバック bintu://** を許可します。アプリはサインアップ確認とパスワード再設定に明示的なコールバック URL を送信するため、リンクをデフォルトの localhost:3000 ではなく Bintu で開きます。Expo Go のリダイレクトは、開発サーバーが実行中で、スマートフォンのネットワークから到達可能な場合にのみ機能します。

Android スマートフォンで実行する

最新の Node.js LTS リリースをインストールし、Android スマートフォンに Expo Go をインストールして、mobile-app/ ディレクトリから次を実行します。

Copy-Item .env.example .env
# Edit .env and set the Supabase project URL and publishable/anon key.
npm install
node .\node_modules\expo\bin\cli start

Expo Go に表示される QR コードをスキャンします。アプリは確認リンクとパスワード再設定リンクを処理し、再設定リンクを開いた後に新しいパスワードを設定できます。EXPO_PUBLIC_ の Supabase キーはクライアント/公開キーであり、サービスシークレットではありません。API がセッションを検証し、Bintu のサーバーキーを非公開に保ちます。ローカルの .env ファイルは git の対象外です。iOS シミュレーターのビルドには macOS と Xcode が必要です。アプリストアで一般公開するには、別途、開発者登録の要件と手数料があります。

これは初期の MVP です。API のインメモリーリミッターは再起動時にリセットされ、アカウントの不正利用防止や月間ユーザー割り当てには対応していません。より多くのユーザーを招待する前に、ホスティングと Supabase のプラン制限を確認してください。

テスト

テストスイートは tests/ パッケージにあり、オフラインで実行できます。接続を差し替えてフェイクレスポンスを使用するため、実際のネットワークリクエストは行いません。

python -m unittest discover -s tests -t . -p "test_*.py" -v

統合テストでは、ループバックポートで実際のローカル HTTP サーバーを実行して、フェッチ、解析、抽出の全パイプラインをテストします。DNS 解決と接続先はモックされるため、SSRF ガードも引き続き適用されます。

python -m unittest tests.test_integration -v

tests/fixtures/extraction_quality/ にある合成ゴールデンフィクスチャは、サードパーティーサイトに依存せず、記事、ナビゲーション要素の多い HTML、テーブルの多い HTML を網羅しています。意図した抽出変更を確認した場合にのみ、フィクスチャと対応する期待値の .txt 出力を更新してください。

GitHub Actions は、プッシュとプルリクエストに対してオフラインのテストスイートを実行します。Render は、CI チェックに合格した後にのみ、リンクされたコミットをデプロイするよう設定されています。デプロイ後、python smoke_check.py を実行して実際の上流フェッチを確認してください(BINTU_BASE_URL と BINTU_API_KEY を設定します)。モックを使ったテストだけでは、上流 HTTP のリグレッションを検出できません。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。