Skip to content

おすすめ台担当 MCP(Cursor) ​

ホールの台データ(差枚・G 数)と機種別・末尾の集計、カレンダー(〇〇の日・イベント・入替)を読んでおすすめ台の案を作り、下書きとして保存するための MCP です。WordPress の REST API recommend/v1 を、おすすめ台担当ロールのユーザーのアプリケーションパスワードで呼びます。編集用・取込用・運用確認用・X告知用・管理者のアカウントは渡しません。

関連: Issue #3900 / 設計 API-009 おすすめ台 REST / ADM-035 権限管理画面 / ADM-037 おすすめ案承認

できること・できないこと ​

操作おすすめ台担当
台データ(日付・台番号・機種 ID・機種名・差枚・G 数)の取得。期間指定・1 台の履歴・1 か月ずつの一括取得できる
機種別サマリ・末尾集計・カレンダー(曜日・〇〇の日・イベント・入替)の取得できる
おすすめ案(ホール×対象日、最大 20 台)の下書き保存・上書き(draft の間だけ)と、保存済みの案・対象日の結果の取得できる
おすすめ案の承認・却下できない
記事への反映・公開できない
BB / RB の取得できない
案の下書き保存以外の書き込み(記事・取込・新台情報・自分のプロフィールやアプリケーションパスワードの変更を含む。アプリケーションパスワード経由の REST(/wp/v2/* を含む)・XML-RPC と wp-admin)できない
wp-admin を開く(ダッシュボード・記事一覧・プロフィールを含む)できない

案の承認・却下は、管理者が管理画面の「サイト運営 > おすすめ案承認」(ADM-037、manage_options)で行います。承認・却下済みの案は bot から上書きできません(409)。

おすすめ台担当ロール(recommend_picker)が持つのは WordPress の read と read_recommend_data・write_recommend_draft だけです。wp-admin を開くとサイトトップへリダイレクトされます。

WordPress は read だけのユーザーにも自分のプロフィール編集とアプリケーションパスワードの発行を許すため、recommend_picker を持ち、他には REST 用 bot ロールしか持たないユーザーには BotWriteGuardHooks で次の制限をかけています(詳細は API-009 の「WordPress コア経由の書き込みの遮断」)。

  • REST は GET / HEAD / OPTIONS と POST /recommend/v1/drafts 以外を 403(/wp/v2/posts の作成、/wp/v2/users/me の更新、アプリケーションパスワードの発行・削除を含む)。他の bot ロールも持たせた場合は、そのロールに許された書き込みも通る
  • 自分自身に対する edit_user とアプリケーションパスワードの発行・編集・削除の権限を外す(管理者による取り消しはできる)
  • XML-RPC にはログインできない

この制限がかかるのは recommend_picker と他の REST 用 bot ロールだけを持つユーザーです。それ以外のロール(購読者・編集者など)を足すと制限が外れるため、兼用しないでください。

ログインパスワードには注意してください。 上の制限はアプリケーションパスワードでのアクセスと wp-admin が対象です。ログインパスワードで wp-login からブラウザにログインすると、フロントの会員プロフィール・退会フォームやコメント投稿などは使えてしまいます。おすすめ台担当ユーザーのログインパスワードは長いランダムな値にし、どこにも保存せず使わないでください。bot にはアプリケーションパスワードだけを渡します。

運用手順(WordPress 側) ​

bot が叩く WordPress(通常は本番)で、管理者が次の作業をします。

1. おすすめ台担当ユーザーを作る ​

  1. 管理画面 → ユーザー → 新規追加
  2. ユーザー名は用途が分かる名前にする(例: recommend-bot)。メールアドレスは管理者が受け取れるものにする
  3. 権限グループで「おすすめ台担当」を選んで追加する
  4. パスワードは長いランダムな値を生成したまま、控えずに追加する(ログインパスワードは使わない。bot にはアプリケーションパスワードだけを渡す)

bot ごと・用途ごとにアカウントを分けてください。 運用確認bot・X告知担当などのアカウントに read_recommend_data / write_recommend_draft を足して兼用しないこと。おすすめ台担当ロールの Capability は ADM-035 権限管理画面 で確認できます(既定は「おすすめ台用データの取得」「おすすめ案の下書き保存」のみ)。

2. アプリケーションパスワードを発行する ​

おすすめ台担当ユーザーは wp-admin を開けないため、管理者が発行します。

  1. 管理者でログイン → 管理画面 → ユーザー → おすすめ台担当ユーザーの編集画面
  2. 「アプリケーションパスワード」で名前(例: cursor-recommend-tools)を入れて追加する
  3. 表示されたパスワード(xxxx xxxx xxxx xxxx xxxx xxxx)を控える。この画面を閉じると二度と表示されません

アプリケーションパスワードは HTTPS のサイトでのみ使えます(ローカルの HTTP では wp-config.php に define( 'WP_ENVIRONMENT_TYPE', 'local' ); が必要)。

3. 本番で権限を確かめる ​

ユーザーを作ったら、そのアプリケーションパスワードで次の 2 つを確かめます(マージ後に人間が行う)。

bash
SITE=https://example.com
AUTH='recommend-bot:xxxx xxxx xxxx xxxx xxxx xxxx'

# 200 になる
curl -sS -o /dev/null -w '%{http_code}\n' -u "$AUTH" "$SITE/wp-json/recommend/v1/coverage"

# 403 になる(コア REST での記事作成は拒否される)
curl -sS -o /dev/null -w '%{http_code}\n' -u "$AUTH" -H 'Content-Type: application/json' \
  -d '{"title":"test","status":"draft"}' "$SITE/wp-json/wp/v2/posts"

4. 失効させる ​

bot をやめるときは、管理者が同じ画面で該当のアプリケーションパスワードを「取り消す」。

5. 漏れた疑いがあるとき ​

漏れたパスワードでできるのは、台データ・集計の読み取りとおすすめ案の下書き保存だけです(記事は変えられず、案も承認しなければ使われません)。それでも念のため、次のどちらかを行ってください。

  • アプリケーションパスワードをすべて取り消し、ログインパスワードもリセットする
  • おすすめ台担当ユーザーを削除して作り直す(確実)

偽の案が保存された可能性がある場合は、管理者が ADM-037 で draft の案を確認し、不要なら却下します。

設定(Cursor 側) ​

  1. .cursor/mcp.json.example を .cursor/mcp.json にコピーする(.cursor/mcp.json は gitignore。パスワードをコミットしない)
  2. recommend-tools の env を書き換える
変数必須説明
WP_SITE_URLはいWordPress のサイト URL。https:// 必須(http:// は localhost / 127.0.0.1 / [::1] / *.local / *.test のみ)。リダイレクトは追わないので、リダイレクト先の URL(www の有無も含む)を書く
RECOMMEND_WP_USERNAMEはいおすすめ台担当ユーザーのユーザー名
RECOMMEND_WP_APP_PASSWORDはいおすすめ台担当ユーザーのアプリケーションパスワード(スペース込みで可)
RECOMMEND_EXPORT_DIRいいえrecommend_export が NDJSON を書き出すディレクトリ。省略時は OS の一時ディレクトリ配下の recommend-export。相対パスは MCP サーバーの起動ディレクトリ基準で絶対パスにする。ディレクトリは 0700、ファイルは 0600 で作る。既存のディレクトリは自分の所有で 0700(他ユーザーに権限なし)でなければ書き出さない(Windows では権限の確認を省く)

他の MCP(OPS_STATUS_WP_*・X_ANNOUNCE_WP_* 等)とは別の変数名です。資格情報を混ぜないでください。

json
{
  "mcpServers": {
    "recommend-tools": {
      "command": "node",
      "args": ["scripts/mcp-recommend-tools.mjs"],
      "env": {
        "WP_SITE_URL": "https://example.com",
        "RECOMMEND_WP_USERNAME": "recommend-bot",
        "RECOMMEND_WP_APP_PASSWORD": "xxxx xxxx xxxx xxxx xxxx xxxx"
      }
    }
  }
}

設定変更後は Cursor を再読み込みし、MCP recommend-tools が有効になっていることを確認します。リポジトリで npm install 済み(@modelcontextprotocol/sdk)であることが前提です。

利用可能な Tool ​

MCP Tool name主な引数REST
recommend_coverage任意 hall、任意 days(1〜92)GET /recommend/v1/coverage
recommend_unitshall, date_from, date_to(最大 31 日)、任意 page, per_page(≤2000)GET /recommend/v1/units
recommend_unit_historyhall, dainum、任意 days(1〜180)GET /recommend/v1/units/{dainum}/history
recommend_exporthall, year、任意 cursor(YYYY-MM)、任意 since(Y-m-d)GET /recommend/v1/export
recommend_kishu_dailyhall, date_from, date_to(最大 92 日)、任意 kishu_ids(整数配列 ≤50)GET /recommend/v1/kishu-daily
recommend_end_numberhall, date_from, date_to(最大 31 日)GET /recommend/v1/end-number
recommend_calendarhall, date_from, date_to(最大 92 日、先の日付も可)GET /recommend/v1/calendar
recommend_drafts_gethall, target_dateGET /recommend/v1/drafts
recommend_draft_savehall, target_date, method_version, items(1〜20 件)、任意 notePOST /recommend/v1/drafts

戻り値は REST のレスポンス JSON そのままです。ただし recommend_export だけは、1 か月分の NDJSON(数 MB になり得る)を RECOMMEND_EXPORT_DIR の {hall}-{YYYY-MM}.ndjson(since の月は {hall}-{YYYY-MM}-since-{Y-m-d}.ndjson。その後の月は月全体なので通常の名前)に書き出し、応答では ndjson の代わりにファイルのパス file を返します(count・month・next_cursor はそのまま)。同じホール・月を取り直すと上書きします。-since- 付きのファイルは since ごとに別名で増えるので、手元のデータに取り込んだら消してください。タイムアウトは recommend_export だけ 180 秒、他は 30 秒です。HTTP エラー・通信失敗・設定不足のときは isError: true で {"error":"...","status":403,"data":{...}} のように返します。429 のときは Retry-After ヘッダーの秒数を retry_after に入れます。入出力とエラー条件の正本は API-009 です。

案を作る流れ ​

  1. recommend_coverage で、ホールの台データが最新日まで揃っているかを確かめる(missing_dates には休業日も入る)
  2. 過去のデータを手元で分析するときは、recommend_export を next_cursor が null になるまで呼び、書き出された NDJSON を読む。1 分あたり 20 回までで、429 になったら retry_after 秒待つ。毎日の更新は月を丸ごと取り直さず、since を渡して差分だけ取る(月をまたぐときは next_cursor と同じ since を渡して続ける)。/export は今日までを返すため、取り込み途中の日の行と samai_step は途中の値のことがある。since は前回取り込んだ日の翌日ではなく、前回の取得時点で recommend_coverage の latest_day だった日の翌日(取り込みが終わっていた日の翌日)にし、それより後の日(部分的に取り込まれていた日)は次回もう一度取り直して上書きする
  3. 直近の傾向は recommend_units・recommend_kishu_daily(必要な機種だけ kishu_ids で絞る)・recommend_end_number・recommend_calendar で取る。気になる台は recommend_unit_history で入れ替え(kishu_changed)がないかを見る。台データの各行の samai_step(150 / 50 / 1)はその日のホールの差枚の刻みで、50 や 150 の日の差枚は丸めた値なので、刻みの違う期間をまたいで差枚を比べるときに使う
  4. 案を recommend_draft_save で保存する。台番号と機種 ID はホールの最新取込日のデータと一致している必要がある(入れ替え前の台番号は 400)。method_version には選定ロジックの版を入れ、ロジックを変えたら上げる
  5. 同じホール・対象日を作り直すときは、そのまま recommend_draft_save を呼べば上書きされる(result: updated、revision が 1 増える)。409(承認済み・却下済み)なら作り直さない
  6. 対象日のあとで recommend_drafts_get を呼ぶと、各台に result(kishu_id・samai・g)が付く。result.kishu_id が案と違えば台が入れ替わっているので、成績の評価から外す

1 ユーザーあたり GET は 1 分 120 回、recommend_export は 1 分 20 回、保存は 1 分 20 回までです(最初の呼び出しから 60 秒の固定ウィンドウ)。超えると 429 になり、Retry-After(秒)が付きます。数えた呼び出しには X-RateLimit-Limit・X-RateLimit-Remaining も付きます。

REST の例(curl) ​

bash
SITE=https://example.com
AUTH='recommend-bot:xxxx xxxx xxxx xxxx xxxx xxxx'

# 台データが揃っているか
curl -sS -u "$AUTH" "$SITE/wp-json/recommend/v1/coverage?hall=island&days=14"

# 期間内の台データ(1 ページ 500 件)
curl -sS -u "$AUTH" "$SITE/wp-json/recommend/v1/units?hall=island&date_from=2026-09-01&date_to=2026-09-30"

# 案の保存
curl -sS -u "$AUTH" -H 'Content-Type: application/json' \
  -d '{"hall":"island","target_date":"2026-10-05","method_version":"v1","items":[{"rank":1,"dainum":"1001","kishu_id":11,"score":0.9,"reason_code":"trend","reason_text":"直近 7 日の平均差枚が上昇"}]}' \
  "$SITE/wp-json/recommend/v1/drafts"

トラブルシューティング ​

症状確認
WP_SITE_URL / RECOMMEND_WP_USERNAME / ... を設定.cursor/mcp.json の recommend-tools.env
HTTP 401(incorrect_password / invalid_username)ユーザー名・アプリケーションパスワードの誤り、取り消し済み、HTTP サイトでの利用
HTTP 403(rest_forbidden、権限がありません)認証ヘッダーが PHP に届いていない、または権限グループが「おすすめ台担当」でない・ADM-035 で「おすすめ台用データの取得」「おすすめ案の下書き保存」が外されている
HTTP 400(台番号・機種が最新取込日と一致しない)recommend_units で最新取込日の台番号と機種 ID を取り直して案を作る
HTTP 409(案が承認済み・却下済み / 台データが 1 日も無い)承認・却下済みの案は上書きできない。台データが無いホールは取込を待つ
HTTP 429GET 1 分 120 回・export 1 分 20 回・保存 1 分 20 回を超えた。retry_after(Retry-After)秒待つ
HTTP 503DB の読み書きの一時的な失敗。時間をおいて同じ内容で呼び直す
NDJSON の書き出しに失敗しましたRECOMMEND_EXPORT_DIR に書き込めるか。symlink は不可。自分の所有で chmod 700 の実ディレクトリを指定する
リダイレクトされましたWP_SITE_URL を location の URL(https / www の有無)に合わせる
HTTP 404(rest_no_route)テーマが本機能を含むバージョンか。パーマリンク設定が「基本」だと /wp-json/ が使えない場合がある
JSON 以外の応答WAF・メンテナンス画面・PHP エラー。body の先頭を確認

403 の切り分けは 新台情報担当 MCP の「403 の切り分け」 と同じ手順(/wp/v2/users/me で認証できているかを見る)です。

実装メモ ​

  • 本体: scripts/mcp-recommend-tools.mjs(テスト: npm run test:mcp-recommend。npm test にも含まれる)
  • 上限値(案の最大 20 台、kishu_ids の最大 50 件)は RecommendationDraftConstants::MAX_ITEMS・RecommendSummaryRestController::KISHU_IDS_MAX と同期する
  • 期間の上限・案の中身の詳しい検証・権限判定・レート制限は REST 側(RecommendRestHandler / WordPressRecommendPermissionChecker)。MCP 側では形式だけを確かめる