Skip to main content
Glama
sptmru

Yandex Eats MCP

by sptmru

Yandex Eats MCP

ChatGPT用のシングルユーザーStreamable HTTP MCPサーバー。https://eats.yandex.com が使用するプライベートWeb APIと直接通信します。ブラウザ自動化は使用しません。

現在のリリース:

  • サーバー設定された1つの配達地点の近くのレストランと一致するアイテムを検索します。

  • レストランの利用可能性と完全なメニューを読み込みます。

  • サーバーサイドのカートを一覧表示および読み取りします。

  • サーバー指示のポーリング、永続的なイベントカーソル、オプションのTelegram配信でアクティブな注文を監視します。

  • 明示的なフィーチャーフラグが有効化された後、成人向けとマークされたアイテムを含むレストランカートアイテムの追加、更新、削除ができます。

  • 永続的なシングルユーザーOAuth 2.1 + PKCEフローで公開MCPエンドポイントを保護します。

  • Yandex Cookie、Passportトークン、正確な座標、電話番号、住所、支払いデータをMCP結果として公開することはありません。

チェックアウト、place_order、ピックアップ、SKU/小売カート、マルチオーダーは意図的に実装されていません。成人向け商品はレストランカートに追加できますが、MCPは資格チェックを迂回したり年齢確認を実行したりしません。これらの要件はYandex Eatsによって引き続き適用されます。カートは注文ではありません。

リスクに関する注意

このプロジェクトは文書化されていないプライベートAPIに依存しています。エンドポイントとレスポンスの形状は予告なく変更される可能性があり、動作はA/Bフラグによって制御される場合があり、自動化された使用はYandexの利用規約やアンチボット対策によって制限される場合があります。CAPTCHAやOTPを自動化しないでください。可能であれば専用アカウントを使用し、別途の法的・セキュリティレビューなしにこのサービスを他のユーザー向けに公開しないでください。

コピーしたCookieヘッダーはYandex Eats以上のアクセスを許可する可能性があります。アカウントのパスワードのように扱ってください。

Related MCP server: bach-yelp_business_api

アーキテクチャ

ChatGPT
   │ HTTPS + OAuth 2.1/PKCE
   ▼
Cloudflare hostname / Tunnel
   │ http://127.0.0.1:3000
   ▼
Docker: yandex-eats-mcp
   │ private Cookie + stable device/session IDs
   ▼
https://eats.yandex.com

プロセスレベルのOrderMonitorはMCPリクエストセッションから独立しています。Yandexの読み取り専用の注文エンドポイントをポーリングし、サニタイズされた状態を/app/state/order-monitor-state.jsonに書き込み、カーソルアドレス可能なイベントを/app/state/order-events.jsonlに追記し、必要に応じて最小限のTelegramメッセージを送信します。

MCPサーバーはスリープ中のChatGPT会話でメッセージを開始できません。ChatGPTはget_order_eventsを定期的に呼び出すことができ(例:Scheduled Taskから)、Telegramはほぼリアルタイムのプッシュチャネルを提供します。

MCPエンドポイントは/mcpです。OAuthディスカバリ、クライアント登録、認可、トークン、保護リソースのメタデータエンドポイントは同じコンテナによって提供されます。OAuthクライアントとハッシュ化されたアクセス/リフレッシュトークンはyandex-eats-state Dockerボリュームに永続化されます。オーナーパスワードはDockerシークレットであり、OAuth状態に永続化されることはありません。

要件

  • Composeを備えたDocker Engine

  • 既存のCloudflare Tunnelと管理下のホスト名

  • ログイン済みのeats.yandex.comブラウザセッション

  • 目的の住所の配達緯度/経度

シークレットの設定

無視されるローカルファイルを作成します。コンテナはUID/GID 1000:1000の非特権nodeユーザーとして実行されるため、シークレットファイルは他のホストユーザーからアクセスできないまま、GID 1000で読み取り可能である必要があります:

mkdir -p secrets
chown root:1000 secrets
chmod 750 secrets
umask 077
openssl rand -base64 32 > secrets/mcp_oauth_password

secrets/yandex_eats_cookieの場合:

  1. Chromeでhttps://eats.yandex.comにサインインします。

  2. DevTools → Networkを開き、ページを再読み込みします。

  3. 認証済みリクエストを選択し、その完全なCookieリクエストヘッダーの値のみをコピーします。

  4. その単一行の値をsecrets/yandex_eats_cookieに入れます。Cookie:プレフィックスは含めないでください。

  5. コンテナのグループに両方のシークレットへの読み取り専用アクセスを許可します:

    chown root:1000 secrets/yandex_eats_cookie secrets/mcp_oauth_password
    chmod 640 secrets/yandex_eats_cookie secrets/mcp_oauth_password

Docker Composeはファイルベースのシークレットを読み取り専用のバインドマウントとして実装するため、root:rootが所有しモード0600のホストファイルは、この非特権コンテナから読み取ることができず、EACCES起動失敗を引き起こします。

どちらのシークレットもChatGPT、シェルコマンドの引数、ログ、イシュー、コミットに貼り付けないでください。

Telegram通知の場合、BotFatherでボットを作成し、宛先チャットIDを確認し、2つの生の値を別々の無視されたファイルに入れます:

printf '%s\n' '<bot token>' > secrets/order_notify_telegram_token
printf '%s\n' '<chat id>' > secrets/order_notify_telegram_chat_id
chown root:1000 secrets/order_notify_telegram_token secrets/order_notify_telegram_chat_id
chmod 640 secrets/order_notify_telegram_token secrets/order_notify_telegram_chat_id

どちらのファイルにも引用符や変数名を含めないでください。ボットは選択したチャットにメッセージを送信できる必要があります。

サービスの設定

cp .env.example .env

.envを編集します:

PUBLIC_BASE_URL=https://eats-mcp.example.com
YANDEX_EATS_LATITUDE=40.000000
YANDEX_EATS_LONGITUDE=44.000000
YANDEX_EATS_CITY=Yerevan
YANDEX_EATS_ADDRESS_LABEL=home
YANDEX_EATS_ENABLE_MUTATIONS=false
YANDEX_EATS_ENABLE_ORDER_MONITORING=true
ORDER_NOTIFY_PROVIDER=telegram

YANDEX_EATS_ADDRESS_LABELはモデルに返される安全なテキストです。正確な座標はクライアント内に留まり、MCPレスポンスに含まれることはありません。

サーバーを起動します:

docker compose up -d --build
docker compose ps
curl http://127.0.0.1:3000/healthz

Composeポートは127.0.0.1にバインドされており、すべてのホストインターフェースにはバインドされていません。

Cloudflare Tunnel

選択したホスト名から以下への公開アプリケーションルートを作成します:

http://127.0.0.1:3000

そのサービスアドレスは、cloudflaredがホスト上で実行されている場合に正しいです。cloudflaredが別のコンテナで実行されている場合は、同じDockerネットワークに配置し、ホストのループバックアドレスの代わりにhttp://mcp:3000にルーティングします。

重要なCloudflare設定:

  • /mcp、/authorize、/token、/register、/revoke、/oauth/*、/.well-known/*をキャッシュしないでください。

  • ストリーミングレスポンスと公開Hostヘッダーを保持します。

  • WAFとレート制限ルールは問題ありませんが、これらのパスの前にインタラクティブなCloudflare Accessログインを配置しないでください。ChatGPTはMCP OAuthディスカバリとコールバックに直接到達する必要があります。

  • PUBLIC_BASE_URLを外部HTTPSオリジンと同一に保ち、/mcpや末尾のパスを含めないでください。

Cloudflare Tunnelはオリジンへの到達可能性を提供します。MCP OAuthフローは依然としてアプリケーションレベルの認可境界です。

ChatGPTから接続する

  1. https://your-domain.example/healthzが{"status":"ok"}を返すことを確認します。

  2. ChatGPT開発者モードで、カスタムMCP/プラグインエンドポイントを追加します:

    https://your-domain.example/mcp
  3. ChatGPTはOAuthメタデータを検出し、Yandex Eats MCP認可ページを開くはずです。

  4. secrets/mcp_oauth_passwordの値を入力します。これはMCPオーナーパスワードであり、Yandexパスワードではありません。

  5. ツールリストを確認します。remove_cart_itemは破壊的です。チェックアウトと注文配置は表示されないはずです。

OAuthオーナーページは、検索/カートアクセスのみを許可することを明示的に記載しています。

ツール

ツール

状態変更

備考

auth_status

いいえ

サニタイズされたCookieセッションステータスのみ

get_delivery_context

いいえ

都市/ラベルのみ、正確な座標は決して含まれない

search

いいえ

不透明なカーソルによる全文検索

get_place

いいえ

利用可能性とETA

get_menu

いいえ

オプションのローカルクエリ/カテゴリフィルタリング

get_cart

いいえ

カートの一覧表示または新しいカートの読み込み

get_active_orders

いいえ

サニタイズされたキャッシュ済みアクティブ注文とモニターヘルス

get_order_status

いいえ

キャッシュされたステータスまたは明示的な読み取り専用リフレッシュ

get_order_events

いいえ

排他的なシーケンスカーソル以降の永続イベント

add_to_cart

はい

現在のメニュー、必須オプション、利用可能性を検証。成人向けマークのアイテムに対応

update_cart_item

はい

明示的なユーザーリクエストのみ

remove_cart_item

はい、破壊的

自動最適化は決して行わない

server_capabilities

いいえ

有効化された安全境界を報告

すべてのミューテーションはオプションのUUID operationIdを受け入れます。10分以内に同じ操作を繰り返すと、上流のミューテーションを繰り返す代わりに同じプロセス内結果が返されます。異なる引数でIDを再利用すると拒否されます。安全でない上流リクエストは自動的に再試行されることはありません。レスポンスが失われたりタイムアウトしたりした場合、ツールはMUTATION_STATUS_UNKNOWNを返します。調整するにはget_cartを呼び出してください。

成功したミューテーションの後、MCPは再読み込みしてサーバーカートを返します。予算チェックは、ローカルの合計ではなく、その新しい合計と違反した制約を使用する必要があります。

注文監視とTelegram

監視はカートのミューテーションから独立しており、読み取りのようなリクエストのみを使用します。以下で有効にします:

YANDEX_EATS_ENABLE_ORDER_MONITORING=true
ORDER_NOTIFY_PROVIDER=telegram

リストとトラッキングの間隔はYandexによって提供され、YANDEX_EATS_ORDER_POLL_MIN_MS / YANDEX_EATS_ORDER_POLL_MAX_MSによってクランプされます。ネットワーク、429、5xxの失敗は制限付きバックオフを使用します。401/403は1つのmonitor.auth_expiredイベントを作成します。Cookieが置き換えられた後、SIGHUPはモニターを即座に起動し、回復はmonitor.recoveredを生成します。

最初の成功したスナップショットはベースラインであるため、モニターをデプロイしても過去の注文については通知されません。その後の発見とフィンガープリントの変更は、単調にシーケンスされたイベントを作成します。Telegramメッセージは注文番号をマスクし、住所、座標、電話番号、支払い、地図ペイロード、配達員の身元を省略します。

ChatGPTからポーリングするには、get_order_eventsからnextSequenceを保持し、afterSequenceとして渡し戻します。カーソルは排他的であり、読み取りは他のクライアントのイベントを確認応答しません。

カートミューテーションの有効化

初期デプロイ中はこれを無効のままにします:

YANDEX_EATS_ENABLE_MUTATIONS=false

まずauth_status、search、get_menu、get_cartを確認します。次に、必須のモディファイアがない使い捨てのレストランアイテムを1つ準備し、フラグを有効にして、制御されたadd_to_cartを実行し、続いてget_cartと新しく作成されたcartItemIdのみの削除を実行します。

YANDEX_EATS_ENABLE_MUTATIONS=true

フラグを変更した後、コンテナを再起動します。テストとしてclear-cartを使用しないでください。意図的に公開されていません。

auth_statusがAUTH_EXPIREDまたはneedsRefresh: trueを報告する場合、secrets/yandex_eats_cookieを新しい単一行のCookie値に置き換え、Dockerシークレットマウントを再作成します:

chown root:1000 secrets/yandex_eats_cookie
chmod 640 secrets/yandex_eats_cookie
docker compose up -d --force-recreate mcp

マウントされたシークレットがその場で更新される非Composeデプロイメント内では、SIGHUPがCookieを再読み込みします:

docker compose kill -s HUP mcp

自動のPassportログイン、OTP、CAPTCHA処理、トークン収集は実装されていません。

開発とテスト

npm install
npm run check
docker compose config
docker compose build

通常のテストスイートはサニタイズされたフィクスチャとモックされた上流レスポンスを使用します。マッパーの耐性、正確なリクエスト配線、曖昧なミューテーションの再試行なし、ミューテーションのシリアライゼーション/冪等性、認証の永続化、MCPツールの注釈を検証します。

読み取り専用のライブコントラクトテストはオプトインであり、ローカルのCookieと座標が必要です:

export YANDEX_EATS_COOKIE_FILE="$PWD/secrets/yandex_eats_cookie"
export YANDEX_EATS_LATITUDE="40.000000"
export YANDEX_EATS_LONGITUDE="44.000000"
npm run test:live:readonly
npm run test:live:orders:readonly

このリポジトリのライブテストは注文を作成しません。通常のテストはYandexに接続することはありません。

運用上の注意

  • /app/state配下の状態には機密性の高いCookieジャーとOAuthデータが含まれます。バックアップを取り、それに応じてDockerホストを保護してください。

  • /readyzは上流リクエストを行わず、注文IDを公開せずにモニターのヘルスを報告します。

  • ログにはエンドポイント、ステータス、所要時間、Yandex相関IDが含まれます。リクエスト/レスポンスボディ、Cookie、認可ヘッダー、セッションID、電話番号、住所、支払いフィールドは編集されるか、ログに記録されません。

  • AUTH_NOT_CONFIGURED:Cookieシークレットが存在しないか、読み取り不能です。

  • AUTH_EXPIRED:新しいブラウザのCookieヘッダーをコピーします。

  • DELIVERY_LOCATION_NOT_CONFIGURED:緯度と経度の両方を設定します。

  • MUTATIONS_DISABLED:フィーチャーフラグが意図的に有効化されるまで想定されます。

  • REQUIRES_CONFIGURATION:get_menuを確認し、ユーザーに必須オプションの選択を求めます。

  • UNSUPPORTED_CART_MODE:現在のリリースはサポートされていないSKU/ピックアップカートフローを拒否します。

  • MUTATION_STATUS_UNKNOWN:盲目的に再試行しないでください。get_cartで調整します。

Related MCP Connectors

Related MCP Servers