Bintu Web Reader について
Bintu Web Readerは、公開HTMLページからAIエージェント向けの読みやすいテキストを抽出するAPIです。ページ構造をMarkdown形式に整え、MCPツールとHTTPエンドポイントを提供します。
主な機能
- 01HTMLから読みやすいテキストを抽出
- 02見出しと表をMarkdown形式で表現
- 03JavaScriptページの任意レンダリング
- 04テキスト上限と切り詰めフラグ
- 05公開URLと応答サイズの検証
- 06短時間の抽出キャッシュ
活用シーン
- 01エージェント向けに公開ページのテキストを抽出
- 02有効化時にJavaScriptページを読み取り
- 03テキスト予算内で抽出内容を確認
MCP 対応
ステートレスなStreamable HTTP MCPエンドポイントで、bintu_scrape_textツールを公開します。MCPツール呼び出しにはスクレイプAPIと同じ認証とレート制限が適用されます。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://bintu-web-reader.mcpize.run/mcpclaude mcp add --transport http l20941485-blip-bintu https://bintu-web-reader.mcpize.run/mcp{"mcpServers":{"l20941485-blip-bintu":{"type":"http","url":"https://bintu-web-reader.mcpize.run/mcp"}}}Cursor で開く{"servers":{"l20941485-blip-bintu":{"type":"http","url":"https://bintu-web-reader.mcpize.run/mcp"}}}VS Code で開く{"mcpServers":{"l20941485-blip-bintu":{"type":"http","url":"https://bintu-web-reader.mcpize.run/mcp"}}}{"mcpServers":{"l20941485-blip-bintu":{"serverUrl":"https://bintu-web-reader.mcpize.run/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
https://bintu-web-reader.mcpize.run/mcp認証が必要ツール
詳細
Bintu Data Extraction API
Bintu は、公開 HTML ページから読み取り可能なテキストを抽出する、FastAPI ベースの API です。上流レスポンスを 1 MiB に制限し、HTML/XHTML のみを受け付け、送信先への接続を検証済みのパブリック IP に固定し、プロセス内で毎分 60 リクエストのバースト制限を適用します。
ライブ API
サービスは Render で稼働中で、テストできます。
- ベース URL:https://bintu-api.onrender.com
- OpenAPI ドキュメント:https://bintu-api.onrender.com/docs
- ヘルスチェック:https://bintu-api.onrender.com/healthz
ヘルスチェック
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 ステータス | エラーコード | 対処方法 |
|---|---|---|
| 400 | invalid_or_unsafe_url, render_js_disabled | 形式が正しいパブリック HTTP または HTTPS の URL を使用してください。プライベートネットワーク宛ての接続はブロックされます。サービスで有効化されていない限り、render_js=true は無効です。render_js=false にして再試行してください。 |
| 401 | invalid_api_key | Render で設定されている現在の X-API-Key を送信してください。 |
| 500 | auth_misconfiguration | REQUIRE_AUTH=true(Render の本番環境でのデフォルト)が設定されていますが、API_KEY と RAPIDAPI_PROXY_SECRET がどちらも空です。Render ダッシュボードでシークレットを復元し、再デプロイしてください。 |
| 413 | payload_too_large | HTML の展開後のサイズが 1 MiB を超えています。 |
| 415 | unsupported_media_type | 対象は HTML または XHTML を返す必要があります。 |
| 429 | burst_rate_limit_exceeded | Retry-After レスポンスヘッダーで指定された秒数だけ待ってから再試行してください。 |
| 502 | upstream_http_error, upstream_connection_error, upstream_render_error, unsupported_content_encoding, too_many_redirects | 対象がエラーを返した、接続またはレンダリングができなかった、サポートされていない圧縮方式が使われた、またはリダイレクトが多すぎました。 |
| 504 | upstream_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 認証とレート制限が適用されます。
クエリパラメーター
| パラメーター | 型 | デフォルト | 説明 |
|---|---|---|---|
url | string | 必須 | スクレイピングする URL |
render_js | bool | false | 抽出前にヘッドレス Chromium で JavaScript をレンダリングします |
include_nav | bool | false | 出力に <nav> 要素を保持します |
include_header | bool | false | 出力に <header> 要素を保持します |
include_footer | bool | false | 出力に <footer> 要素を保持します |
サービス制限
- リクエストのタイムアウト:接続試行ごとに10秒です。
- リダイレクト:最大5回です。遷移先ごとにURLとDNSの検証を繰り返します。
- HTML本文:展開後で最大1 MiBです。4 KiB以下のチャンク単位で読み込みます。Gzip圧縮されたHTMLも、展開後のサイズ制限は同じです。
- テキストレスポンス:最大6,000文字です。コンテンツが上限を超えると、
truncatedはtrueになります。テキストは、取得可能な最後の単語の境界で切り詰められます。 - JavaScriptのレンダリング:デフォルトでは無効です(
RENDER_JS_ENABLED=false)。render_js=trueを指定すると、400render_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_SECONDS | 300 | プロセス内HTMLキャッシュのTTL(秒)。0 にするとそのキャッシュは無効になります(Supabaseの24時間キャッシュとは別です)。数値以外の値、または範囲外の値(許容範囲は0~86400)は、ログに警告を記録して300にフォールバックします |
REDIS_URL | (空) | 複数インスタンスでのレート制限に使用するRedis URL。空または接続不可の場合は、プロセスごとのバースト制限(フェイルオープン)となり、各インスタンスが独自のウィンドウを適用します |
RENDER_JS_ENABLED | false | JavaScriptレンダリングのキルスイッチ。値が厳密に true の場合のみChromiumが有効になります。それ以外の場合、render_js=true に対して400 render_js_disabled が返されます |
BINTU_UPGRADE_URL | https://mcpize.com | MCP 401 -32001 の upgrade_url に埋め込まれる正規の登録URLです。エージェントがチャット内にクリック可能なリンクを表示します |
Renderへのデプロイ
- このプロジェクトをGitHubリポジトリにプッシュします。
- Renderで新しいBlueprintを作成し、そのリポジトリを選択します。Renderは
render.yamlを読み込み、requirements.txtとChromiumのシステム依存関係をインストールした後、割り当てられたポートでUvicornを起動します。 /healthzが正常になるまで待ちます。直接APIにアクセスする場合は、サービス環境から生成されたAPI_KEYをコピーします。どちらのシークレットもコミットしないでください。- 公開する前に、デプロイ済みの
/docsページをテストし、認証済みのスクレイピングリクエストを実行します。
無料インスタンスはアイドル状態の間にスリープすることがあるため、最初のリクエストは遅くなる場合があります。無料サービスは検証や初期ユーザー向けであり、レイテンシに厳しい本番環境や稼働時間の保証には適していません。ローカルのバースト制限は再起動時にリセットされ、インスタンス間で共有されません。有料クォータではないため、課金の基準としてRapidAPIのプラン制限を使用してください。
ストアフロントの同等性(単一の信頼できる情報源)
1 つの API、3 つの窓口です。動作は同一で、異なるのはゲートウェイごとの認証と課金のみです。
| Direct(Render) | RapidAPI | MCPize | |
|---|---|---|---|
| 掲載名 | サービス 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 プロバイダーのシークレットがアプリに送信されることはありません。
バックエンドを設定する
- Supabase プロジェクトを作成し、メール/パスワード認証を有効にします。メール確認は有効のままにしてください。
- Supabase プロジェクトの設定で、プロジェクト URL と公開可能キー(または従来の anon キー)をコピーします。
service_roleキーやシークレットキーは使用しないでください。 - Render サービスの環境変数に
SUPABASE_URLとSUPABASE_ANON_KEYを設定します。既存の生成済みAPI_KEYは非公開のままにしてください。 - 永続的なスクレイピングキャッシュと 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 のリグレッションを検出できません。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。