mcpField
A
Address Validator

Address Validator

リモート
kder-ai.com地図・旅行01 週間前に更新
リポジトリ公式サイト

Address Validator について

Address Validatorは、配送先住所の標準化とジオコーディングを必要とするサービス向けの従量課金HTTP APIです。配達可能性と信頼度のスコア、キャッシュキーを返し、プロバイダーが停止している場合は縮退結果を返します。

主な機能

  1. 01認識された配送先住所を標準化
  2. 02緯度・経度を返却
  3. 03配達可能性と信頼度のスコアを提供
  4. 04重複する住所の結果をキャッシュ
  5. 05プロバイダー障害時に縮退レスポンスを返却

活用シーン

  1. 01出荷処理前に住所を正規化
  2. 02住所の座標と配達可能性を確認
  3. 03プロバイダー停止時の住所検証を継続

MCP 対応

x402またはMCPディレクトリ向けに、サービスとスキーマを説明する`/manifest`を提供します。READMEにはMCPツールやMCPサーバーインターフェースの説明はありません。

設定

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

エンドポイントhttps://kder-ai.com/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 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。

ツール

1
パラメーター型必須説明
addressanyはい

詳細

住所検証 API

リクエストごとに課金される HTTP API(x402 プロトコル、デフォルト価格 0.02 USDC)です。未加工の配送先住所を受け取り、標準化した住所、 その座標、配達可能性スコア、キャッシュキーを返します。

1. 概要

  • 唯一の有料エンドポイント:POST /validate — 有効な支払い証明がない場合は 402 Payment Required を返します。
  • 出力:標準化された住所(line1、line2、city、state、zip、 country)。住所が認識された場合はプロバイダーによって修正されます(D84: 綴り、市区町村、郵便番号の追加)。latitude/longitude(Nominatim によるジオコーディング)、deliverability、 confidence、degraded、cache_key。
  • サービスの検出:GET /manifest は、x402/MCP ディレクトリ向けにサービスと そのスキーマを記述します。
  • 耐障害性:プロバイダーに接続できない場合でも、API は degraded: true を付けて 200 を返します — 住所が確実に無効だと思わせる エラーは返しません。

仕様の成功基準と、自動検証箇所:

#基準検証
1支払い証明なしの呼び出しは 402 を受け取る(価格とプロトコルが通知される)tests/test_payment.py(8 件のテスト)、tests/test_routes_extra.py::test_metrics_count_unpaid_requests、scripts/e2e_check.py
2有効な支払い証明を伴う呼び出しは 200 と結果を受け取るtests/test_cache.py(実際の有料呼び出し)、tests/test_validation.py::test_valid_address_with_mocked_provider、scripts/e2e_check.py
3キャッシュにより、同じ住所でプロバイダーを再度呼び出さずに済むtests/test_cache.py::test_second_identical_request_hits_cache と ::test_distinct_requests_call_provider_twice、scripts/e2e_check.py
4プロバイダーの障害時に、明示的な縮退応答を迅速に返すtests/test_validation.py::test_degraded_flag_set_when_provider_unreachable、tests/test_circuit_breaker.py、tests/test_latency_budget.py

このサービスが行わないこと:アプリケーションレベルのレート制限はありません(D21)— 制限は Nginx の edge レベルで適用されます(nginx-hardening.conf:IP ごとに 10 リクエスト/秒、バースト 20、それを超えると 429)。従来の支払い方式(共有シークレットによる HMAC 証明、D15)は、 署名だけでは受け付けなくなりました:W1 のセキュリティ強化(12/10/2026)以降、 オンチェーン確認(D27)がデフォルトで有効になっており、Base 上で 入金用ウォレットへの確認済み USDC 送金を要求します。合成 HMAC 証明で 200 を取得できるのは、 宣言されたレシピ(TEST_MODE=true)でのみです。この場合、書き込まれる行には test_mode のマークが付き、実際の収益から除外されます(D40)。すべての内容は 隠すのではなく、文書化されています(README.md §7 および §9、SECURITY.md §3 および §6、AUDIT_TRAFIC_VPS.md §5)。

2. クイックスタート

前提条件:Python 3.12(リポジトリの venv は、Dockerfile の python:3.12-slim イメージと同じく 3.12.10 で動作します)。PostgreSQL と Redis は 任意です:これらがなくても API は起動し、適切に縮退します(/health で確認できます)。

# 1. Environnement virtuel
py -3.12 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt -r requirements-dev.txt

# 2. Configuration (jamais de secret dans le dépôt)
Copy-Item .env.example .env        # renseigner SMARTY_AUTH_ID / API_SECRET_KEY / clés CDP

# 3. Lancer l'API
.\.venv\Scripts\python.exe -m uvicorn app.main:app --reload --port 8000
# Vérifications
.\.venv\Scripts\python.exe -m pytest -q                  # suite complète
.\.venv\Scripts\python.exe scripts\run_tests.py          # oracle de tests (rapport JUnit)
.\.venv\Scripts\python.exe scripts\doc_check.py README.md 10   # sections de ce fichier
.\.venv\Scripts\python.exe scripts\e2e_check.py http://127.0.0.1:8000   # recette bout-en-bout

コンテナでの起動:docker compose up -d(docker-compose.yml と Dockerfile を参照)。

本番環境へのデプロイ(Debian 12 VPS、Nginx + HTTPS、x402 支払い): DEPLOIEMENT_VPS.md — 実運用の記録、計画との差異として許容した点、 運用上の注意事項。

3. 設定

すべての値は環境変数または .env から取得します(pydantic-settings、 app/config.py)。不明な変数は無視されます(決定 D8)。

項目変数デフォルト役割
api_host / api_portAPI_HOST / API_PORT127.0.0.1 / 8000uvicorn のリッスン先(127.0.0.1:サービスは Nginx 経由で公開され、直接公開されません)
api_secret_keyAPI_SECRET_KEYchange_me支払い証明の HMAC キー — 必ず変更してください
database_urlDATABASE_URLpostgresql://user:password@localhost:5432/address_validatorPostgreSQL(支払いログ)
redis_urlREDIS_URLredis://localhost:6379/0結果のキャッシュ
smarty_auth_id / smarty_auth_tokenSMARTY_AUTH_ID / SMARTY_AUTH_TOKEN空検証プロバイダーの認証情報
cdp_api_key_id / cdp_api_key_secretCDP_API_KEY_ID / CDP_API_KEY_SECRET空Coinbase CDP SDK(任意)
cdp_wallet_addressCDP_WALLET_ADDRESS空402 で通知されるウォレット
x402_priceX402_PRICE0.02検証ごとの価格(USDC)
x402_onchain_verifyX402_ONCHAIN_VERIFYtrueUSDC 転送のオンチェーン確認(D27、W1 からデフォルトで有効)— false が許可されるのは TEST_MODE=true の場合のみです。受け入れテスト以外では、共有シークレットによる証明はすべて拒否されます — §7 を参照
base_rpc_urlBASE_RPC_URLhttps://mainnet.base.orgD27 が有効な場合に使用する Base JSON-RPC ノード(チェーン 8453)
x402_usdc_contractX402_USDC_CONTRACT0x833589…4bda02913Base のネイティブ USDC コントラクト
x402_min_confirmationsX402_MIN_CONFIRMATIONS1支払いを受け入れる前に必要な最小確認数
x402_network / x402_chain_idX402_NETWORK / X402_CHAIN_IDbase / 8453accepts[] で通知されるネットワークとチェーン
x402_domain_name / x402_domain_versionX402_DOMAIN_NAME / X402_DOMAIN_VERSIONUSD Coin / 2トークンの EIP-712 ドメイン — scripts/test_x402_payment.py --check-domain によってオンチェーンで検証されます
x402_facilitator_urlX402_FACILITATOR_URLhttps://api.cdp.coinbase.com/platform/v2/x402ファシリテーター(/verify の後に /settle)
x402_facilitator_verifyX402_FACILITATOR_VERIFYtrue決済前に /verify を呼び出します
x402_require_settlementX402_REQUIRE_SETTLEMENTtrue入金後にのみサービスを提供します(false は本番環境では禁止)
public_base_url / mcp_public_urlPUBLIC_BASE_URL / MCP_PUBLIC_URLhttps://kder-ai.com / .../mcpaccepts[].resource、MCP カード、ディレクトリで公開される URL
discovery_log_*DISCOVERY_LOG_ENABLED, DISCOVERY_LOG_PATH, DISCOVERY_LOG_RAW_IP, DISCOVERY_LOG_SALT, DISCOVERY_LOG_RETENTION_DAYSログ有効、パスは空(journald)、IP は仮名化、30 日402 の拒否ログと適用される保持期間(PRIVACY.md 3)
dashboard_user / dashboard_passwordDASHBOARD_USER / DASHBOARD_PASSWORDkder / 空/dashboard — 空の場合はエンドポイントが閉鎖されます(503)。IP ごとに LOGIN_MAX_FAILURES 回パスワードを間違えると、LOGIN_LOCK_MINUTES 分間ブロックされます(D67)
geoip_db_path / audience_retention_daysGEOIP_DB_PATH / AUDIENCE_RETENTION_DAYS/var/lib/address-validator/dbip-country.mmdb / 400オーディエンス追跡(D67):scripts/maj_geoip.sh で配置される DB-IP Lite の国データベース(存在しない場合は国不明);page_visits および api_calls 行の保持期間
pilotage_comptesPILOTAGE_COMPTES空ダッシュボードのアカウント(D74)。「名前=email」の形式でカンマ区切り。公開リポジトリのコードには絶対に含めないでください
cost_server_eur / cost_smarty_eur / cost_smarty_per_call_usd / cost_mail_eurCOST_SERVER_EUR / COST_SMARTY_EUR / COST_SMARTY_PER_CALL_USD / COST_MAIL_EUR0ダッシュボードが読み取るコスト(D68):すべて 0 の場合、当月の結果は計算されません
test_mode / test_mode_cutoff_utcTEST_MODE / TEST_MODE_CUTOFF_UTCfalse / 2026-10-11T12:00:00+00:00test_mode とマークされたトランザクションは受け入れテストです。real_* から除外され、test_* と total_* に計上されます(D40)
environment / log_levelENVIRONMENT / LOG_LEVELdevelopment / INFO環境とログの詳細度

4. エンドポイントとデータ契約

メソッドパス役割ソース
GET/サービスの識別情報とリンクapp/main.py:57-65
GET/manifestx402 の説明(価格、通貨、スキーマ)app/routes/manifest.py
GET/healthPostgreSQL と Redis の実際の状態。タイムアウトは 2 秒app/routes/health.py
GET/metricsカウンター、サーキットブレーカーの状態、キャッシュの状態app/routes/metrics.py
GET/metrics/revenue24 時間/7 日/30 日の集計収益 — real_* はテスト環境を除外、total_* はレジストリ全体(D40)— およびレジストリの可用性app/routes/revenue.py
GET/dashboard運用ダッシュボード — 非公開(Basic Auth。DASHBOARD_PASSWORD が未設定の場合は 503。IP ごとにパスワードを 5 回間違えると 15 分間ブロック、D67)。D67 以降、公開ページへの訪問と API 呼び出しはそれぞれ追跡行を記録します(国、参照元、所要時間、ステータス。IP と Cookie は記録しません)。D69 以降、v2 デザイン(サイドバー、結果の大型カード、ドットマップ、ソース・robots・ページを含むサイトと SEO、訪問から有料利用までの経路)。D68 以降、収支画面(実際の入金額、請求予定のサブスクリプション、コスト、結果、予測、国別・チャネル別収益)、API画面(ステータス、応答時間、キャッシュ、チャネル、国)、顧客画面(期限切れになるトライアル、クォータ、未使用アカウント)、アラート、期間 `?p=jour7j
GET/dashboard/argent, /dashboard/api, /dashboard/clients, /dashboard/site, /dashboard/registre運用管理の各セクションのページ(D71)。/dashboard と同じアクセス制御。期間は ?p= で保持app/routes/dashboard.py, app/pilotage_page.py
GET POST/dashboard/mot-de-passe, /dashboard/nouveau-mot-de-passeダッシュボードアカウント(D74):PILOTAGE_COMPTES に登録されたメールアドレスに、パスワードを設定するリンクを送信します(有効期限 30 分、1 回限り、データベースにはハッシュのみを保存、bcrypt ハッシュ)。アドレスが未登録の場合も同じ応答を返します。アカウントごとに 1 時間あたり 3 件のリンクを発行。以後はメールアドレスでログインapp/pilotage_comptes.py, app/routes/dashboard.py
GET POST/dashboard/connexion, /dashboard/deconnexionダッシュボードのログインページ(D69)。Basic 認証のダイアログに代わり、署名付き Cookie __Host-av_pilotage(HMAC、12 時間、HttpOnly、Secure、SameSite=Strict)を使用します。同じく 5 回失敗すると 15 分間ロックされ、別サイトからのフォーム送信は拒否されます。セッションのないブラウザーはログインページにリダイレクトされ、スクリプトには Basic 認証のチャレンジが表示されますapp/routes/dashboard.py, app/pilotage_page.py
GET/prospection営業開拓 CRM(一覧、フィルター、マーク、エクスポート)— 非公開。/dashboard と同じアクセス制御(パスワードが未設定、または PROSPECTION_DB が存在しない場合は 503)app/routes/prospection.py, prospection/README.md
GET/pricing商用プランの公開ページ(D43)— 公開、インデックス登録可能、5 分間キャッシュ。外部リソースは使用せず、/dashboard とスタイルシートを共有(app/web.py)app/routes/pricing.py
GET POST/signupセルフサービス登録(D44)— 公開。パスワードは bcrypt でハッシュ化し、API キー sk_live_ は一度だけ表示。IP ごとに 1 時間あたり 5 件の登録app/routes/signup.py, app/accounts.py
GET POST/validate-form公開無料トライアル(D46)— 公開、インデックス登録可能。IP ごとに 24 時間あたり 3 回まで(D94。超過時は 429 と正確な Retry-After を返します)。書き込みは行わず、何も読み込みません。劣化した結果はその旨を明示します。1 行の住所(フィールド address、D86)も受け付けますapp/routes/validate_form.py, app/ratelimit.py
POST/stripe/webhookStripe 決済(D91):署名付きの checkout.session.completed(Stripe-Signature、HMAC-SHA256、5 分)が届くと、client_reference_id のアカウントを有料プランに切り替えます(2 900 → Starter、7 900 → Pro)。customer.subscription.deleted が届くと、期限切れのトライアルに戻します。STRIPE_WEBHOOK_SECRET が未設定の場合は 503app/routes/stripe_webhook.py, app/accounts.py
GET/robots.txt, /sitemap.xml, /favicon.ico検索エンジン最適化(D65)— 検索エンジンと AI に公開されたサイト。公開ページを 6 言語と各 hreflang で掲載するサイトマップ、アイコン。公開ページには `` ブロック(canonical、Open Graph、JSON-LD)が含まれます。www. は PUBLIC_BASE_URL に 301 リダイレクトしますapp/seo.py
GET/819a36fb2a9140f4f142b6e80ae19cc3.txtIndexNow キー(D81)。設計上公開されています。scripts/indexnow.py --envoyer はサイトマップのページを Bing、Yandex、Seznam、Naver に通知しますapp/seo.py
GET/guide公開連携ガイド(D48)— 公開、インデックス登録可能、5 分間キャッシュ可能。シークレットは含みません。JSON 契約、戻りコード、キャッシュ、クォータ、直接呼び出し/CSV/Shopify/WooCommerce の例を記載app/routes/guide.py
GET/agents, /compareコンテンツページ(D66)— 公開、インデックス登録可能、6 言語対応。AI エージェント向け住所検証(MCP、x402、アカウント不要)と、Google、Smarty、PostGrid、Geoapify の公表価格の比較(2026/10/14 時点の調査、出典を明記、「どのサービスを選ぶか」)。当社の数値はコードと設定に基づいていますapp/routes/contenu.py
GET POST/compte, /compte/cle顧客ページ:月次ダッシュボード(D64:月次の数値、アカウントの状態から推定した次のステップ、日ごとのグラフ、アドバイス)、API キー、プランと請求 — 非公開(/compte/connexion でログインするか、スクリプトから送信された Basic Auth を使用。セッションがない場合はログインページに 303 リダイレクト。キーの再生成にはパスワードの再入力が必要。データベースが応答しない場合は 503)app/routes/signup.py, app/accounts.py
GET POST/compte/connexion, /compte/deconnexion顧客ページへのログイン(D62)— 非公開ページ(no-store、noindex)。Cookie __Host-av_session(ランダムトークン。データベースにはハッシュのみを保存。有効期限は最大 12 時間)。パスワードを 5 回間違えると、IP とアカウントごとに 15 分間ブロックされます。別サイトからのフォーム送信は拒否されますapp/routes/connexion.py
GET POST/compte/mot-de-passe-oublie, /compte/nouveau-mot-de-passeパスワードを忘れた場合(D63)— PUBLIC_BASE_URL を使用して生成するメール内リンク。データベースにはハッシュのみを保存。有効期限 30 分、1 回限り。アカウントの有無にかかわらず同じ応答を返します。アカウントごとに 1 時間あたり 3 通、IP ごとに 1 時間あたり 5 件のリクエストまで。新しいパスワードを設定すると、すべてのセッションを終了します。SMTP_HOST 経由で送信(空の場合はメールを送信しません)app/routes/mot_de_passe.py
POST/validate有料 — 完全な検証。2 つの支払い方法:サブスクリプション(X-API-Key、D45)または呼び出しごとの決済(x402/HMAC 証明)app/routes/validate.py
GET/docsインタラクティブドキュメント(FastAPI)自動
GET/llms.txt, /AGENTS.md, /.well-known/security.txtエージェント向けの検出ファイル。Nginx が静的ファイルとして配信します(DISCOVERY.md を参照)nginx-discovery.conf
POST/mcpMCP サーバー(JSON-RPC 2.0):検出は無料、tools/call は有料(x402 v2 トランスポート:支払いは params._meta["x402/payment"] に指定し、オファーとレシートはツールの結果に含めます。ヘッダー X-PAYMENT による v1 も受け付けます)app/routes/mcp.py
GET/.well-known/mcp-serverMCP 検出カード(アプリケーションが配信)app/routes/mcp.py
GET/.well-known/x402x402 検出マニフェスト(IETF ドラフト draft-hawkins-x402-dns-discovery-03)。アプリケーションが配信します。/openapi.json では API のみを公開します(D95)app/routes/manifest.py
拒否された 402 リクエストは、メタデータ(タイムスタンプ、エンドポイント、User-Agent、仮名化された IP)の形式で記録されます。検証済みの住所が記録されることはありません。設定と保持期間については、PRIVACY.md §3、DISCOVERY.md §4 を参照してください。
4.1 実収益とレジストリ収益(D40)

/metrics/revenue は同じレジストリについて、混同することなく3種類の値を公開します。

フィールド内容
real_validations_paid, real_revenue_usdcクライアントが支払った金額 — 公開可能な数値
total_validations_paid, total_revenue_usdcリハーサルを含むレジストリ全体(監査用)
test_validations_paid, test_revenue_usdc実収益から除外される金額。real_* + test_* = total_*

エイリアス validations_paid と revenue_usdc(D31)は実収益を指します。 トランザクションが test_mode としてマークされる方法は、次の2つだけです。 サービスが記録する時点での TEST_MODE=true(リハーサル中)、または すでに記録済みの行に対する scripts/migrate_test_mode.py の実行です。しきい値は TEST_MODE_CUTOFF_UTC(デフォルトは 2026-10-11T12:00:00+00:00。その日の2件の リハーサル)です。金額や住所から推測されることはありません。マークされていない行は実収益のままです。/dashboard では実収益を先頭に表示し、リハーサルは専用のカードに表示します。

すでに記録済みのレジストリは、再デプロイせずに遡及処理できます。 venv/bin/python scripts/migrate_test_mode.py(行ごとのシミュレーション)を実行してから、 --apply を指定します。再実行しても新たな書き込みは発生しません(冪等性)。結果は curl -s http://127.0.0.1:8000/metrics/revenue で確認できます。

リクエスト(app/schemas.py:11-16):{"address": {"street", "city", "state", "zip", "country"}} — country のデフォルト値は US です。それ以外のフィールドは必須です(フィールドが欠けている場合は 422)。

レスポンス(app/schemas.py:19-37):{"result": {"validated", "standardized", "latitude", "longitude", "deliverability", "confidence", "degraded", "cache_key"}, "price_paid", "transaction_id"}。

検証パイプライン(app/validation/__init__.py:26-41): parse → standardize → verify (fournisseur) → geocode → score。D84 以降、認識された住所は、ジオコーディングの前に、プロバイダーが修正した形式(corrige)で parse → standardize を再実行します。

出力意味
degraded: trueプロバイダーに問い合わせできませんでした(障害、タイムアウト、サーキットブレーカーが開いている状態)。その場合、deliverability は invalid になりますが、住所が存在しないことの証拠にはなりません
deliverability / confidenceDPV コードに基づきます:Y → residential 0,99;S → residential 0,95;D → commercial 0,99;X → unknown 0,50;N → invalid 0,00;座標を取得できた場合は +0,05(app/validation/scorer.py:17-36)
cache_key正規化された生の住所の SHA-256 ハッシュです。キャッシュ項目を識別し、削除に使用できます(PRIVACY.md §5 を参照)
4.2 同じ検証に対する2つの支払い方法(D45)

POST /validate は2種類のクライアントに対応します。APIキーを提示するサブスクリプション契約店舗と、呼び出しごとに支払う(§5)自律型エージェントです。APIキーが優先されます。両方が送信された場合はサブスクリプションが適用され、呼び出しに対するUSDCの請求は行われません。

モード入力ヘッダー引き落とされるものprice_paid
サブスクリプションX-API-Key: sk_live_…アカウントのカウンター(customer_validations)0.0
x402 / HMACX-PAYMENT または X-Payment-Proof支払い台帳(D29)0.02(USDC)

レスポンスには X-Payment-Mode(api_key、x402、hmac)が含まれます。これがなければ、クライアントはサブスクリプションでカバーされた呼び出しか、請求された呼び出しかを区別できません。APIキーモードでは、アカウントの状態を示す2つのヘッダー、X-Plan と X-Quota-Remaining も返されます(無制限プランでは省略され、省略されている場合は「無制限」を意味します)。

状況コードこのコードになる理由
有効なキーで、当月のクォータに空きがある200リクエストを処理し、アカウントから引き落とします。USDC台帳はそのままです
不明なキー(または空のキー)401修正が必要なのはクライアントの設定です
無料トライアル終了(trial プラン)403アカウントは存在しますが、サービスを利用できなくなっています
月間クォータを使い切った402利用上限であり、認証の失敗ではありません
アカウントデータベースに接続できない503検証されていないキーは、拒否されたキーではありません。402 は決して返しません

クォータは /pricing に掲載されているとおり月単位です。期間は暦月のUTC(accounts.month_start())で、累計カウンターは /compte に引き続き表示されますが、利用を制限することはありません。拒否時の本文は判別可能で({"mode": "api_key", "reason": "cle_inconnue" | "compte_expire" | "quota_atteint"})、キーのプレフィックス(sk_live_ab12)のみを含み、次の手段(upgrade → /pricing)を示します。

$cle = "sk_live_..."   # affichée une seule fois à l'inscription, régénérable sur /compte
$corps = '{"address":{"street":"1 Rue de Paris","city":"Saint-Denis","state":"RE","zip":"97400","country":"RE"}}'
$r = Invoke-WebRequest -Uri http://127.0.0.1:8000/validate -Method POST `
     -Headers @{ "X-API-Key" = $cle } -ContentType "application/json" -Body $corps
$r.Headers["X-Payment-Mode"], $r.Headers["X-Plan"], $r.Headers["X-Quota-Remaining"]
$r.Content | ConvertFrom-Json | Select-Object price_paid, transaction_id
# -> api_key  trial  99 ; price_paid = 0.0, transaction_id = $null

X-API-Key ヘッダーなしの同じ呼び出しは、引き続きx402で課金されます。APIキーモードによって、自律型エージェントの機能が損なわれることはありません。/metrics で公開されるカウンター:api_key_requests、api_key_validations、api_key_denied、api_key_unavailable。

4.3 公開無料トライアル(D46)

GET /validate-form は公開ページを提供します。検索エンジンに登録可能で、5分間キャッシュでき、単独で動作します。スクリプトも外部リソースも使わず、共有スタイルシート(app/web.py)を使用します。訪問者が最初に目にするページであり、CSP(form-action 'self')により、コードの約束をブラウザーで検証できます。

項目動作
上限VALIDATE_FORM_RATE_LIMIT_PER_DAY(デフォルトは10)により、IPアドレスごとに24時間あたり10回まで試行できます。期間は固定で、最初の試行時に開始し、拒否のたびに延長されることはありません
拒否429 + 正確な Retry-After(期間の残り秒数)。上限を再掲し、/signup へのリンクを表示します
書き込みなし:customers、customer_validations、payment_transactions への書き込みはありません。validate_form_requests / validate_form_validations / validate_form_denied のカウンターのみが増加します
パイプライン/validate と同じ(perform_validation):判定もキャッシュも同じです
キャッシュとインデックス登録空のフォームは public, max-age=300 でキャッシュされ、インデックス登録されます。結果、エラー、拒否を含むすべての POST レスポンスは、住所を含むため no-store + noindex です
劣化時の結果その旨を表示します:「プロバイダーから応答がありません。この応答から住所について何も判断できません」——住所が無効だとは決して表示しません
入力エスケープして再表示し、修正できるようにします。2文字でない国コードは、プロバイダーを呼び出す前に拒否されます(400)

上限カウンターは /metrics で確認できます。上限による拒否をカウントすることで初めて、「誰も試していない」のか「全員がブロックされている」のかを区別できます。

4.4 公開統合ガイド(D48)

GET /guide は、キーを受け取ったばかりのクライアントが知りたいことに答えます。認証(X-API-Key または x402)、正確な JSON 仕様、実行すべきアクションを含む8 つの戻りコード、キャッシュされる情報と上限が設けられる情報、さらに 4 つの実用例(PowerShell での直接呼び出し、Python での CSV インポート、Shopify、WooCommerce)です。

項目動作
公開される情報公開データベース、価格、無料トライアルの上限、ヘッダー X-Payment-Mode / X-Plan / X-Quota-Remaining、プラン:コードと設定から読み取られ、転記されることはありません(置換されていないひな形はゲートが拒否します)
シークレットありません。このページはインデックス可能であり、設計上公開されています。サンプルキーはひな形です(sk_live_VOTRE_CLE)
自立性スクリプトなし、外部リソースなし、共有スタイルシート、Cache-Control: public, max-age=300、form-action 'none'
ナビゲーション定義は 1 か所のみ(app/web.py: site_head()):/guide はすべての公開ページからアクセスでき、/pricing は独自の <nav> のコピーを持たなくなりました
明示する制限Shopify アプリも WooCommerce 拡張機能も提供されません(呼び出しはクライアント側のサービスから行います)。degraded の結果は「再確認が必要」であり、無効な住所ではありません
4.5 ショップ向けウェルカムメール(D49)

ページではなく、アカウントを作成したばかりのショップに送信するメッセージです。EMAIL_BIENVENUE.md にあり、2 つの形式で提供されます。n8n に読み込むひな形(変数 {{…}} は表で説明)と、最初のクライアント(Tiitoune Art)向けの送信準備済みのメールです。

項目動作
数値トライアル日数、無料クォータ、月額料金はコード(accounts.JOURS_ESSAI、VALIDATIONS_ESSAI)と /pricing から読み取られます。これらが反映されていないメールはゲートが拒否します
案内する方法サブスクリプション(X-API-Key):X-PAYMENT、X-Payment-Proof、tx_hash は含みません。ゲートはこのメッセージでこれらを禁止しています(呼び出しごとの支払いはエージェント向けの方法であり、/guide に記載されています)
シークレットキーは一切含みません。本文では /signup と /compte を案内します。ゲートは完全な sk_live_ キーや、リポジトリのデフォルト値を拒否します
明示する制限自動引き落としなし、住所について「何も示さない」degraded、保存されるのは指紋(住所ではありません)、cache_key による消去
送信メール本文に差し込み変数が残っていないこと(確認済み)、ひな形の各変数が説明されていること(確認済み)
4.6 顧客追跡(D50)

追跡表の価値は、実際に提供されている内容と一致しているかどうかで決まります。 アカウントテーブルにすでに含まれている情報で、収益を左右する唯一の問いに答えられます。どのアカウントが存在し、どのアカウントがひそかに失われつつあり、何を伝えるべきか? ルールは app/suivi.py(状態、しきい値、緊急度の順序)に、実行処理は scripts/suivi_clients.py にあります。

# rapport lisible, sur la base de la configuration (DATABASE_URL)
.\.venv\Scripts\python.exe scripts\suivi_clients.py

# export pour un tableur, seuils resserrés
.\.venv\Scripts\python.exe scripts\suivi_clients.py --format csv --sortie suivi.csv --essai-bientot-jours 5

# expliquer après coup un classement : rejouer le rapport à une date donnée
.\.venv\Scripts\python.exe scripts\suivi_clients.py --maintenant 2026-10-01T09:00:00+00:00
項目動作
公開状態有料ルートの状態:accounts.plan_status / consumption / refusal_reason と、REFUS_HTTP で読み取るHTTPコードです。しきい値を複製しないため、食い違いは生じません
順序緊急度の順です。まず現在拒否されているもの、次に試用期間の終了が近いもの、またはクォータにまもなく達するもの、その次に初期設定が完了していないものです。同じ優先度の場合は、期限が最も近いものを先にします
シークレットキーのプレフィックス(電話でアカウントを識別するためのもの)のみを使用し、キー全体もそのフィンガープリントも使用しません。有効性が確認されたメールアドレスは読み取りません
読み取り専用SELECT のみです。レポートから本番データベースを変更することはできません
エクスポート--format csv はUTF-8、区切り文字「;」(フランス語版Excel向け)、改行コード \n で書き込みます。スクリプトは書き込み時にこれを通知します
戻りコード0 はレポートを生成(空のデータベースも測定結果です)、2 は何も測定できなかったことを示します。空のレポートは「すべて順調」という意味ではありません

検証:.\.venv\Scripts\python.exe scripts\decisions_check.py D50 — このゲートでは実際のデータベースを用意し、公開状態とルートが適用する拒否内容を比較します。試用期間が終了した有料顧客のケースも対象です。

4.7 ホームページ(D53)

GET / はブラウザー向けにサイトのトップページを提供し、プログラム向けには従来のJSONを維持します(どちらにも Vary: Accept を設定)。デザインは app/templates/accueil/fr.html にあります(元のモックアップ:docs/maquettes/page-accueil/)。試用期間、クォータ、価格、x402価格、連絡先などの数値は、コードと設定から app/routes/accueil.py によって挿入されます。

curl.exe -s https://kder-ai.com/                      # JSON, comme avant
curl.exe -s -H "Accept: text/html" https://kder-ai.com/   # la vitrine

検証:.\.venv\Scripts\python.exe scripts\decisions_check.py D53。

4.8 6言語対応(D57)

フランス語はルートに置き、ほかの5言語にはプレフィックスを付けます。公開ページはすべて6言語で利用できます。サイトのトップページ、ガイド(D58)、無料トライアル(D59)、料金(D60)、登録ページと顧客ページ(D61)が、それぞれフランス語のURLの前に言語プレフィックスを付けたアドレスで提供されます(/en/guide、/ar/signup など)。

言語ホーム表示通貨(請求はユーロ)
フランス語/29 € / 79 €
英語/en/$33 / $90
中国語/zh/¥223 / ¥608
ヒンディー語/hi/₹3,160 / ₹8,620
スペイン語/es/29 € / 79 €
アラビア語(右から左)/ar/$33 / $90

app/i18n.py は各言語のアドレス(chemin(lang, page))、数値と価格(prix、mention_euros、2026年9月の為替レート)を生成し、テンプレートをレンダリングします(rendre)。ユーロ建ての金額は accounts.OFFRES(pricing.OFFRES からも参照可能)に基づきます。換算後の表を更新せずに価格を変更すると、tests/test_i18n.py とD57ゲートのチェックが失敗します。写真はアプリケーションから /images/ で配信されます。公開CSPで許可されるのは img-src 'self' のみです。

curl.exe -s https://kder-ai.com/en/                              # la vitrine en anglais
curl.exe -sI https://kder-ai.com/images/commercante-colis.jpg    # image/jpeg, nosniff

検証:.\.venv\Scripts\python.exe scripts\decisions_check.py D57。

4.9 AI エージェントと訪問:ブロックせずに測定する(D72、D73)

サービスは、呼び出し元を6つの分類(agent_ia、 annuaire_mcp、moteur、outil、navigateur、inconnu)に分類し、AI エージェントとMCP ディレクトリのアクセスをD30のJSONLログに記録します(人間による訪問は記録しません)。また、5つの指標(agents、top_ip、top_agents、 top_pages、conversion)を公開します。エージェントは一切ブロックされません。/pricingを読むエージェントは、ブラウザーを使わない見込み客です。各社が公開している25のAI エージェントの許可リストは、docs/AGENTS-IA.mdと /metrics/agentsのレスポンスにあります。

curl.exe -s https://kder-ai.com/metrics/agents                        # en direct (compteurs du processus)
.\.venv\Scripts\python.exe scripts\analyser_agents.py --since 7d      # ce qui est écrit (journal JSONL)
.\.venv\Scripts\python.exe scripts\analyser_visites.py --since 24h    # tout le trafic (journal Nginx), 7 sections

scripts/analyser_visites.pyは、7つのセクション(主要指標、時間、人気ページ、人気IP、ステータスコード、クライアント、異常(プローブ、機密性の高いパス、漏えい))を出力します。IPアドレスは、--ip-en-clairを明示的に指定しない限り、仮名化されます(SHA-256+ソルト、D30)。漏えいとは、機密性の高いパスが2xxで配信されることです(301は別の場所に転送するため、情報を公開しません)。2つの解析ツールは同じ分類テーブルを参照するため、エンドポイントとレポートでエージェントの定義が食い違うことはありません。

確認:.\\.venv\\Scripts\\python.exe scripts\\run_tests.py tests\\test_agents_ia.py tests\\test_visites.py。

4.10 フランスの住所:Base Adresse Nationale(D79)

PAYS_BANの国(フランス本土および海外領土:FR、RE、 GP、MQ、GF、YT、BL、MF、PM)では、検証はBase Adresse Nationale(app/validation/ban.py、https://data.geopf.fr/geocodage)を通じて行い、フランスの住所を判定できないSmartyStreetsは決して使用しません。

  • BANスコアが0.8以上であること、返された郵便番号が入力された郵便番号と一致すること、市区町村名が一致すること(アクセント、大小文字、ハイフン、句読点を正規化);
  • housenumber(0,99)とstreet(0,95)のタイプのみを使用します。その他(municipality、locality)では道路が認識されていません;
  • BANが停止した場合はdegraded: trueを返し、SmartyStreetsにはフォールバックしません;
  • 米国では、DPVコードY/S/Dのみが住所を有効とします。XとNでは有効にならず、DPVのない候補ではdegraded: trueを返します。

この修正前に計算されたフランス本土/海外領土の結果(キャッシュ期間30日)は、scripts/purger_cache_ban.pyで削除できます(デフォルトはシミュレーション、削除するには--applyを指定)。2026年10月17日の測定では、「8 rue madelaine, Lyon, 75005」はvalidated: true(キャッシュ)からvalidated: falseに変わり、Paris 75002、Lyon 69001、Saint-Denis 97400は引き続き有効です。

5. 有料呼び出しの例

  1. 証明を作成します(クライアントとAPIでAPI_SECRET_KEYを共有します)。
.\.venv\Scripts\python.exe -c "from app.payment import build_payment_proof; print(build_payment_proof('0x-demo-tx'))"
# -> 0x-demo-tx:1770000000.123:<hmac_sha256_hex>
  1. APIを呼び出します。
curl.exe -X POST http://127.0.0.1:8000/validate `
  -H "Content-Type: application/json" `
  -H "X-Payment-Proof: 0x-demo-tx:1770000000.123:<hmac>" `
  -H "X-Transaction-Id: 0x-demo-tx" `
  -d "{\"address\":{\"street\":\"1600 Amphitheatre Parkway\",\"city\":\"Mountain View\",\"state\":\"CA\",\"zip\":\"94043\",\"country\":\"US\"}}"
  1. 証明がない場合、または期限切れ/不正な形式/偽造された証明の場合、レスポンスは402です(app/payment.py:77-85)。
{"error": "Payment Required", "price": 0.02, "currency": "USDC",
 "wallet": "", "protocol": "x402", "version": "1.0"}

上記で公開している402の本文は抜粋です。x402Version、network、accepts[](x402 v1オファー)も含まれ、さらに現在はaccepts[0].outputSchema(ValidationResponseのPydanticスキーマ、D80)も含まれます。2026年10月17日の測定では、本文は1,788バイトで、ヘッダーはnginxの4 KBバッファー内に収まり、v2の同じオファーはPAYMENT-REQUIREDヘッダーに含まれます。

  1. 有効な証明がある場合、レスポンスは200です。2026年10月10日にこのマシンでステージング環境にて測定した例です(プロバイダーに接続できなかったため、degraded)。
{"result": {"validated": false, "standardized": {"line1": "1600 Amphitheatre Parkway", "...": "..."},
            "deliverability": "invalid", "confidence": 0.05, "degraded": true,
            "cache_key": "8f1c…"},
 "price_paid": 0.02, "transaction_id": "0x-demo-tx"}

transaction_idは、受信したX-Transaction-Idヘッダーをそのまま反映します(app/routes/validate.py:67)。

本番環境で同じ呼び出しを行った場合の例(2026年10月11日、https://kder-ai.com、実際のプロバイダーが稼働中、有効なHMAC証明)。

{"result": {"validated": true, "deliverability": "residential", "confidence": 1.0,
            "degraded": false, "cache_key": "250a6087…"},
 "price_paid": 0.02, "transaction_id": null}

deliverabilityはプロバイダーから返されるDPVコードに基づいています(Y → residential、scorer.py:17-23)。また、confidenceにはジオコーディングのボーナスが加算されます(0,99 + 0,05、上限1,0)。プロバイダーのmetadata.rdi(この住所ではCommercial)は未加工データに残り、APIからは公開されません。

6. キャッシュ、レジリエンス、レイテンシ予算

メカニズム動作決定
Redis キャッシュキー addr:<sha256>、TTL 30 日、ネットワーク呼び出しの前に参照D5
劣化結果の TTL5 分であり、30 日ではありません。degraded: true は「プロバイダーが応答しなかった」ことを示し、「アドレスが無効」であることを示すものではありません。1 か月保持すると一時的な障害が固定化されてしまいます。5 分保持すれば、障害中のプロバイダーへのリクエストの集中を防ぐには十分です。一方、検証済みの判定は 30 日保持しますD47
キャッシュのクールダウンバックエンドでエラーが発生した後、キャッシュは 30 秒間利用不可と見なされます。Redis の障害によるコストは 1 回だけ発生し、リクエストごとには発生しません。/health は実際のプローブを維持しますD25
Redis タイムアウト接続 1 秒、読み取り 1 秒。エラーカウンターを公開D12
プロバイダーのサーキットブレーカーclosed → open → half-open → closed、アプリケーションレベルのしきい値はエラー 3 回、回復時間は 60 秒。開状態になると、ローカルで即座に応答しますD23
プロバイダーのタイムアウト個別に設定:接続 2 秒、読み取り 4 秒(全体で 10 秒ではありません)D23
ジオコーダーのタイムアウト接続 2 秒、読み取り 3 秒。失敗してもリクエスト全体を失敗させず、latitude/longitude は null のままになりますD26
/health プローブイベントループ外で並列実行し、上限を 2 秒に設定D22
オブザーバビリティサーキットブレーカーの状態とキャッシュの可用性を /metrics で公開D24

この環境で 10/10/2026 に測定したレイテンシ(PostgreSQL と Redis は停止、 外向きネットワークは有効、プロバイダーの認証情報は空のため応答は 401):

測定項目値方法
GET /health2,13 s実際の HTTP リクエスト(D22 の上限:2,0 s に到達。2 つのプローブはいずれも失敗)
POST /validate 有料、1 回目の呼び出し11,117 sscripts/e2e_check.py
POST /validate 有料、2 回目の呼び出し11,036 sscripts/e2e_check.py
Redis 読み取り、バックエンド不在2,03 sプロセス内で測定(D25 によりコストが発生するのは 1 回のみ)
プロバイダー呼び出し(401 を 3 回再試行)6,77 sプロセス内で測定
Nominatim ジオコーディング0,86 sプロセス内で測定
パイプライン全体(validate_full)7,62 sプロセス内で測定

これらの数値は正直なものであり、見栄えのよいものではありません。劣化時のレイテンシはプロバイダーの影響が大きく、そのエラーはバックオフによって再試行されます(TEST_REPORT.md の「既知の制限」を参照)。 コードに記録されている基準値(D23 より前は 15,2 s、D22 より前は 6,03 s)は、今日再測定されていません。TEST_REPORT.md では過去の値として記載されています。

7. x402 決済:検証されるもの、決済されるもの、従来の仕組みとして残るもの

このサービスはx402 v1(リポジトリ coinbase/x402 の仕様 specs/transports-v1/http.md)を採用し、Base 上で実際に USDC 決済を行います。402 の本文は PaymentRequired ドキュメントです。

{ "x402Version": 1, "error": "...", "accepts": [ { "scheme": "exact",
  "network": "base", "maxAmountRequired": "20000", "asset": "0x833589…2913",
  "payTo": "0x0fe9…d339", "resource": "https://kder-ai.com/validate",
  "mimeType": "application/json", "maxTimeoutSeconds": 300,
  "extra": { "name": "USD Coin", "version": "2" } } ] }

クライアントは署名を X-PAYMENT(PaymentPayload の base64 エンコード {signature, authorization:{from,to,value,validAfter,validBefore,nonce}})で返し、X-PAYMENT-RESPONSE({success, transaction, network, payer} の base64 エンコード)を受け取ります。

x402 v2 にも対応(D77)。 同じ 402 が、PAYMENT-REQUIRED ヘッダーに v2 のオファーを含みます(ネットワーク eip155:8453、フィールド amount、Coinbase カタログの拡張 bazaar)。v2 クライアントは PAYMENT-SIGNATURE で支払い、PAYMENT-RESPONSE を受け取ります。支払い手段がない場合、本文が空でも /validate は 402 を返します。これは Coinbase カタログのチェックが期待する動作です。

次の順序で行う2つの検証(app/x402.py):

  1. ローカルでオフライン検証 — EIP-712 ダイジェスト(TransferWithAuthorization、EIP-3009)を明示的に再計算し(eth_abi、eth_hash、eth_keys)、復元した署名を authorization.from と照合します。また、送信先、金額、トークン、ネットワーク、有効期間を公開済みのオファーと照合します。この検証に通るまで、サーバーから外部へ情報が送信されることはありません;
  2. 決済 — ファシリテーターに POST /verify、続けて POST /settle を送信します(デフォルトは Coinbase のファシリテーターで、CDP_API_KEY_ID / CDP_API_KEY_SECRET を使用して署名した JWT CDP で認証します)。決済ハッシュは永続レジストリに記録されます(D29)。明示的な拒否、障害、ハッシュの欠落、決済済み nonce のいずれも拒否として扱います。

通知される EIP-712 ドメイン(extra.name / extra.version)には、コントラクトの値が使用されます。scripts/test_x402_payment.py --check-domain でオンチェーン検証できます。2026年10月11日に Base で測定した値は、name() = "USD Coin"、version() = "2"、decimals() = 6 です。

従来の仕組みとして残るもの(D15)。 X-Payment-Proof ヘッダー(tx_hash:timestamp:hmac_sha256)は、運用者向けツールと統合済みクライアントのために引き続き受け付けます。有効期間は前後300秒で、HMAC は時間差に依存しない方法で比較します。また、Base 上のレシート確認が必須です(D27。デフォルトで有効。TEST_MODE=true が明示されたレシピだけが対象外)。確認には JSON-RPC を使用します(app/onchain.py。web3 パッケージも鍵ストアパッケージも使用しません)。HMAC による支払いを x402 の決済として扱うことはありません。HMAC には X-PAYMENT-RESPONSE が含まれないためです。

MCP。 同じツールを MCP として POST /mcp で公開します(JSON-RPC 2.0、ステートレス、SSE ストリームなし)。D78 以降、決済はMCP x402 v2 トランスポートに従います。支払いなしの tools/call は、structuredContent に v2 の PaymentRequired を含む isError: true のツール結果を返します(content[0].text にも同じドキュメントが含まれ、ネットワークは CAIP-2、リソースは mcp://tool/validate_address です)。クライアントは v2 の PaymentPayload を params._meta["x402/payment"] に入れ、result._meta["x402/payment-response"] で決済結果を受け取ります。このトランスポートでは JSON-RPC の 402 は送信されません。x402 MCP クライアントは HTTP ステータスではなく結果を読み取るためです。D34/D37 との互換性は維持しており、v1 クライアントは X-PAYMENT で支払い、決済ヘッダーを引き続き使用できます。2つのトランスポートの検証と入金処理には、唯一の経路として settle_payment を使用します。GET /.well-known/mcp-server のカードはアプリケーションから提供されるため、停止中のエンドポイントが記載されることはありません。ディレクトリへの公開:server.json、.mcp.json、smithery.yaml(DISCOVERY.md §1 を参照)。

実際の決済テスト。 scripts/test_x402_payment.py には3つのモードがあります。plan(/manifest、402 の本文、MCP トランスポートのオファーで同じオファーが公開されていることを確認)、--check-domain(通知されたドメインをオンチェーンのコントラクトと比較)、--pay(実際の決済。Base 上で USDC を入金済みの購入者ウォレットが必要で、0.02 USDC を使用します)。

8. テストと検証

ツール検証内容コマンド
pytestユニットテストおよび統合テストの動作.\.venv\Scripts\python.exe -m pytest -q
scripts/run_tests.pyテストオラクル:pytest の要約行(リダイレクトされた出力では表示されなくなる)に依存せず、JUnit XML レポートと終了コードを出力します.\.venv\Scripts\python.exe scripts\run_tests.py
scripts/doc_check.pyドキュメントに、期待される数の ## N. セクションが正確に含まれ、番号に抜けがないこと.\.venv\Scripts\python.exe scripts\doc_check.py README.md 10
scripts/e2e_check.py4 つの成功基準を網羅する 22 項目の実際の HTTP テスト.\.venv\Scripts\python.exe scripts\e2e_check.py http://127.0.0.1:8000
GATES.mdゲート台帳:実行可能なオラクル(CHECK: / EXPECT:)と手動レビュー下記「台帳の実行方法」を参照
.cline/skills/unlazy/scripts/gate-lint.mjsオラクルが実際に失敗すること(台帳の品質)node .cline\skills\unlazy\scripts\gate-lint.mjs GATES.md

このマシンで 10/10/2026 に測定した結果:46 tests collectés — 45 passés, 1 ignoré(無視されたテストは、実際の SmartyStreets 認証情報とネットワークを必要とする統合テストです);scripts/e2e_check.py → 22/22 vérifications OK。詳細、方法、制限事項については TEST_REPORT.md を参照してください。

プロジェクトのルートから台帳を実行する方法:

node .cline\skills\unlazy\scripts\gate-lint.mjs address-validator\GATES.md
node .cline\skills\unlazy\scripts\gate-check.mjs --status  address-validator\GATES.md   # lit, n'exécute rien
node .cline\skills\unlazy\scripts\gate-check.mjs --approve address-validator\GATES.md   # approuve après lecture
node .cline\skills\unlazy\scripts\gate-check.mjs           address-validator\GATES.md   # exécute les oracles approuvés

9. デプロイ

deploy.sh は Debian/Ubuntu VPS を対象とし、次の処理を順に実行します:パッケージのインストール (python3.12、PostgreSQL、Redis、Nginx、Certbot)、/opt へのクローン、 仮想環境の作成、pip install -r requirements.txt、PostgreSQL データベースと ユーザーの作成、Redis の有効化、nginx.conf のコピー、証明書の取得 (certbot --nginx)、続いて systemd サービスのインストールと起動。 スクリプトは set -euo pipefail(D20)で実行されるため、最初の エラーで停止します。

注意点:deploy.sh は .env ファイルを作成しません。 手動で設定しないと、 サービスはデフォルト値で起動します。つまり、API_SECRET_KEY=change_me、 PostgreSQL のパスワードは change_me のままで、SmartyStreets の認証情報もありません (この場合、プロバイダーは 401 を返し、すべての応答が劣化します)。デプロイ直後に次を実行してください:

# sur le serveur, dans /opt/address-validator
cp .env.example .env        # puis renseigner API_SECRET_KEY, SMARTY_*, DATABASE_URL, REDIS_URL
systemctl restart address-validator
systemctl status address-validator
curl -s http://127.0.0.1:8000/health
journalctl -u address-validator -n 50

コンテナーを使用する方法:docker compose up -d(python:3.12-slim をベースにした Dockerfile、API とその依存関係用の docker-compose.yml)。

本番 VPS(kder-ai.com)のデプロイ:scripts/deploy-kder-ai.sh — サーバーで実際に実行されたスクリプトで、ここでバージョン管理されています (11/10/2026 より前は、ワークステーションと /opt にしかなく、バージョン管理の対象外でした)。 上記の 11 ステップを実行し、さらに次を追加します:

  • API_SECRET_KEY がまだ change_me のまま、または 32 文字未満の場合、 あるいは .env が CRLF の場合、デプロイを拒否します;
  • nginx-hardening.conf を /etc/nginx/conf.d/ にインストールします:HSTS (1 年間、includeSubDomains)、X-Content-Type-Options: nosniff、 Referrer-Policy: no-referrer、IP ごとに limit_req を 10 req/s(バースト 20)に設定し、 リクエスト本文を 16 ko に制限します。これは意図的に仮想ホストの外に配置しています。 仮想ホストは certbot --nginx が更新のたびに書き換えるためです;
  • 強化設定が失われている場合に失敗する(または通知する)チェック: 127.0.0.1:8000 のみでリッスンしていること(10.6)、セキュリティヘッダー(10.7)、 60 件の同時呼び出しに対する 429(10.8);
  • Debian リポジトリで Python 3.12 が提供されていない場合の代替手段として、 Python 3.12 をコンパイルします。

実際のデプロイ記録(バージョン、ログ、想定された差異、11/10/2026 の修正)は DEPLOIEMENT_VPS.md にあります。

本番環境へのデプロイ後は、/metrics と /docs へのアクセスを制限し、Redis のパスワードを有効にして、 Nginx による HTTPS リダイレクトが正しく設定されていることを確認してください (SECURITY.md §4 および §6)。

10. 既知の制限と今後の対応

制限影響ドキュメントの記載箇所
宣言されたテスト設定(TEST_MODE=true)では、オンチェーンを照会せずに共有シークレットによる証明を受け付けます運用者によるテスト専用です。書き込まれた行には test_mode のマークが付き、実際の収益から除外されます。テスト設定以外では、USDC の送金が確認されていない証明には 402 が返されます§7、SECURITY.md §3、D27、D40、D42
証明は300秒間リプレイできます同じ証明をウィンドウ内で複数回使用できます§7、SECURITY.md §6
address_validations にデータが一度も書き込まれませんデータベースにアドレスの記録は残りません。保持は Redis キャッシュ(30日)に依存しますPRIVACY.md §3
record_transaction は記録がない場合、処理を拒否しますD41以降、書き込みに失敗すると 500(ledger_write_failures_total)が返されます。支払いは受理されますが、検証は提供されず、入金を照合する必要がありますSECURITY.md §5、D41
有料プランの有効期限がありません手動で付与したプランは、手動で取り消すまで有効です。利用を制限するのは月間クォータのみです(D45)。自動課金がないため、適用すべきサブスクリプションの終了日はありませんSECURITY.md §3、D45
コードに製品レベルのレート制限が2つあり、不正利用対策は edge が担いますNginx は不正利用対策として、IP ごとに毎秒10リクエスト(バースト20、超過時は 429)に制限します。コードでは、クライアントに通知されるビジネス上の制限を追加します。/signup はIPごとに1時間あたり5件の登録(D44)、また /validate-form では、3つ目の項目としてIPごとに24時間あたり3回の無料試行(D21改訂版)です§9、SECURITY.md §6、D21(改訂版)、D44
メトリクスがメモリ内に保存されます再起動時に失われ、Prometheus へのエクスポートもアラートもありませんSECURITY.md §5
プロバイダーの4xxエラーが再試行されます測定された遅延は11.1秒に悪化しています。バックオフは再試行できないエラーに対して適用されますTEST_REPORT.md、「既知の制限」
CORS *、/metrics、/docs が公開され、コードではデフォルトのシークレット change_me も引き続き受け付けられますさらに強化する必要があります。ただし、デプロイ時には change_me と32文字未満のすべてのシークレットが拒否されます(scripts/deploy-kder-ai.sh)§9、SECURITY.md §2および§6
フランス本土・海外領土のカバレッジBase Adresse Nationale(D79)で確認済みです。スコア、郵便番号、都市名を検証します。BAN の障害時は degraded となり、判定は行いません。修正前にキャッシュされた結果は一度だけ削除されます(scripts/purger_cache_ban.py)§4.10、D79
402 の契約outputSchema(派生した出力スキーマ)とルートの network が公開されています。本文は約1.8 KBとなり、ヘッダーは4 KB未満に収まります§5、§7、D80
deploy.sh は .env を作成しません手動の手順を忘れると、デフォルトのシークレットで起動します§9

推奨される今後の対応(優先度順):

  1. プロバイダーへの再試行はネットワークエラーと5xxに限定します。これにより、401 に対するバックオフをなくし、悪化時の遅延を約3秒未満に抑えられます。
  2. 支払い証明を消費して(リプレイを防止)、API_SECRET_KEY がデフォルト値のままの場合は起動を拒否します。
  3. メトリクスを実際の監視システムに接続し、デプロイ時に .env を生成します。

コメント

MCP は初めてですか?

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

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