Appearance
X告知担当 MCP(Cursor)
公開済みの日別記事・有料記事を X で告知するとき、告知に使う記事のメタ情報(URL・タイトル・考察日・号数・アイキャッチ URL・告知履歴)を読み、X に投稿した結果を記事に記録するための MCP です。WordPress の REST API x-announce/v1 を、X告知担当ロールのユーザーのアプリケーションパスワードで呼びます。編集用・取込用・運用確認用・管理者のアカウントは渡しません。
関連: Issue #3885 / 設計 API-007 X告知 REST / ADM-035 権限管理画面
できること・できないこと
| 操作 | X告知担当 |
|---|---|
| 公開済み日別記事のメタ情報(URL・タイトル・考察日・公開/更新日時・アイキャッチ URL)と告知履歴 | できる |
| 公開済み有料記事のメタ情報(URL・タイトル・号数・対象月・無料公開フラグ・公開/更新日時・アイキャッチ URL)と告知履歴 | できる |
X に投稿した結果(tweet_id・投稿日時・種類)を記事の告知履歴に記録する | できる |
| 記事の本文・考察欄・抜粋・有料記事の冒頭挨拶やセクションの取得 | できない |
| 下書き・予約・非公開の記事の取得 | できない |
| 告知履歴の記録以外の書き込み(記事・取込・新台情報・自分のプロフィールやアプリケーションパスワードの変更を含む。アプリケーションパスワード経由の REST・XML-RPC と wp-admin) | できない |
| wp-admin を開く(ダッシュボード・記事一覧・プロフィールを含む) | できない |
| X への投稿 | できない |
告知文の要約は各記事の編集 bot が作ります。X告知担当は本文を読まず、編集 bot から受け取った要約と、この MCP で取ったメタ情報で告知文を組み立てます。
X告知担当ロール(x_announcer)が持つのは WordPress の read と read_x_announce・record_x_announcement だけです。wp-admin を開くとサイトトップへリダイレクトされます。
WordPress は read だけのユーザーにも自分のプロフィール編集とアプリケーションパスワードの発行を許すため、x_announcer を持ち、他には REST 用 bot ロール(ops_status_reader / birthday_linker)しか持たないユーザーには BotWriteGuardHooks で次の制限をかけています(詳細は API-007 の「権限・nonce・レート制限」)。
- REST は GET / HEAD / OPTIONS と POST
/x-announce/v1/announcements以外を 403(/wp/v2/users/meの更新、アプリケーションパスワードの発行・削除を含む) - 自分自身に対する
edit_userとアプリケーションパスワードの発行・編集・削除の権限を外す(管理者による取り消しはできる) - XML-RPC にはログインできない
birthday_linkerを併せ持つユーザーは birthday/v1 の決められた書き込みも通り、拒否時のエラーコードはbirthday_write_forbidden/birthday_xmlrpc_forbiddenになる
ログインパスワードには注意してください。 上の制限はアプリケーションパスワードでのアクセスと wp-admin が対象です。ログインパスワードで wp-login からブラウザにログインすると、フロントの会員プロフィール・退会フォームやコメント投稿などは使えてしまいます。X告知担当ユーザーのログインパスワードは長いランダムな値にし、どこにも保存せず使わないでください。bot にはアプリケーションパスワードだけを渡します。
X の資格情報
X の API キー・アクセストークンは bot 側のシークレットにだけ置き、WordPress には保存しません。この MCP も X には投稿しません。X への投稿は bot が自分の資格情報で行い、投稿できたあとに x_announce_record で結果だけを WordPress に記録します。
運用手順(WordPress 側)
bot が叩く WordPress(通常は本番)で、管理者が次の作業をします。
1. X告知担当ユーザーを作る
- 管理画面 → ユーザー → 新規追加
- ユーザー名は用途が分かる名前にする(例:
x-announce-bot)。メールアドレスは管理者が受け取れるものにする - 権限グループで「X告知担当」を選んで追加する
- パスワードは長いランダムな値を生成したまま、控えずに追加する(ログインパスワードは使わない。bot にはアプリケーションパスワードだけを渡す)
bot ごと・用途ごとにアカウントを分けてください。 日別記事編集bot・運用確認bot などのアカウントに read_x_announce / record_x_announcement を足して兼用しないこと。X告知担当ロールの Capability は ADM-035 権限管理画面 で確認できます(既定は「告知用メタ情報の取得」「告知履歴の記録」のみ)。
2. アプリケーションパスワードを発行する
X告知担当ユーザーは wp-admin を開けないため、管理者が発行します。
- 管理者でログイン → 管理画面 → ユーザー → X告知担当ユーザーの編集画面
- 「アプリケーションパスワード」で名前(例:
cursor-x-announce-tools)を入れて追加する - 表示されたパスワード(
xxxx xxxx xxxx xxxx xxxx xxxx)を控える。この画面を閉じると二度と表示されません
アプリケーションパスワードは HTTPS のサイトでのみ使えます(ローカルの HTTP では wp-config.php に define( 'WP_ENVIRONMENT_TYPE', 'local' ); が必要)。
3. 失効させる
bot をやめるときは、管理者が同じ画面で該当のアプリケーションパスワードを「取り消す」。
4. 漏れた疑いがあるとき
漏れたパスワードでできるのは、公開済み記事のメタ情報の読み取りと告知履歴の記録だけです(記事本体は変えられません)。それでも念のため、次のどちらかを行ってください。
- アプリケーションパスワードをすべて取り消し、ログインパスワードもリセットする
- X告知担当ユーザーを削除して作り直す(確実)
偽の告知履歴が記録された可能性がある場合は、管理者が該当記事の _x_announcements を確認します。
この制限がかかるのは x_announcer だけ(または x_announcer と ops_status_reader だけ)を持つユーザーです。他のロールを足すと外れるため、兼用しないでください。
設定(Cursor 側)
.cursor/mcp.json.exampleを.cursor/mcp.jsonにコピーする(.cursor/mcp.jsonは gitignore。パスワードをコミットしない)x-announce-toolsのenvを書き換える
| 変数 | 必須 | 説明 |
|---|---|---|
WP_SITE_URL | はい | WordPress のサイト URL。https:// 必須(http:// は localhost / 127.0.0.1 / [::1] / *.local / *.test のみ)。リダイレクトは追わないので、リダイレクト先の URL(www の有無も含む)を書く |
X_ANNOUNCE_WP_USERNAME | はい | X告知担当ユーザーのユーザー名 |
X_ANNOUNCE_WP_APP_PASSWORD | はい | X告知担当ユーザーのアプリケーションパスワード(スペース込みで可) |
他の MCP(OPS_STATUS_WP_*・DAILY_ARTICLE_WP_* 等)とは別の変数名です。資格情報を混ぜないでください。
json
{
"mcpServers": {
"x-announce-tools": {
"command": "node",
"args": ["scripts/mcp-x-announce-tools.mjs"],
"env": {
"WP_SITE_URL": "https://example.com",
"X_ANNOUNCE_WP_USERNAME": "x-announce-bot",
"X_ANNOUNCE_WP_APP_PASSWORD": "xxxx xxxx xxxx xxxx xxxx xxxx"
}
}
}
}設定変更後は Cursor を再読み込みし、MCP x-announce-tools が有効になっていることを確認します。リポジトリで npm install 済み(@modelcontextprotocol/sdk)であることが前提です。
利用可能な Tool
| MCP Tool name | 主な引数 | REST |
|---|---|---|
x_announce_daily_articles | date_from, date_to(最大 31 日) | GET /x-announce/v1/daily-articles |
x_announce_daily_article | id | GET /x-announce/v1/daily-articles/{id} |
x_announce_paid_articles | 任意 modified_after(前回の modified_gmt か ISO 8601) | GET /x-announce/v1/paid-articles |
x_announce_paid_article | id | GET /x-announce/v1/paid-articles/{id} |
x_announce_record | post_id, kind, tweet_id, posted_at | POST /x-announce/v1/announcements |
x_announce_settings | なし | GET /x-announce/v1/settings |
戻り値は REST のレスポンス JSON そのままです。HTTP エラー・通信失敗・設定不足のときは isError: true で {"error":"...","status":403,"data":{...}} のように返します。入出力とエラー条件の正本は API-007 です。
告知の流れ
- 告知する記事を探す。日別記事は
x_announce_daily_articlesに考察日の期間を、有料記事はx_announce_paid_articlesに前回取得時のmodified_gmt(2026-09-30 15:00:00の形式のまま)をmodified_afterで渡す announcementsに同じkindの履歴があれば、告知済みなのでスキップする- 編集 bot から受け取った要約と、
url・title等のメタ情報で告知文を組み立てる。画像を添付するときはfeatured_image_urlを使う(nullなら画像なし) x_announce_settingsで投稿方法を確認する。kindがdaily_*ならposting_modes.daily_article、paid_updateならposting_modes.paid_articleを見る。設定は途中で変わり得るため、告知のたびに呼ぶapiのとき: 人間の承認後、bot が X に投稿する。投稿できたらx_announce_recordにpost_id・kind・X のtweet_id(文字列)・posted_atを渡す。result: created(201)なら記録済み。タイムアウトなどで結果が分からないときは同じ内容で再送してよい(result: duplicateが返り、履歴は増えない。重複の判定は記事ごとに保存している最新 20 件が対象)manualのとき: X には投稿せず、告知文とurl・featured_image_urlを人間に渡して終わる。人間が投稿した分は告知履歴に記録しない(x_announce_recordは呼ばない)。そのため手順 2 の「告知済み」の判定は効かないので、同じ記事を二重に渡さないよう人間側で確認する(有料記事は更新のたびにmodified_afterの結果に再び出るため、特に注意する)
投稿方法は管理画面の「サイト運営 > X告知設定」(ADM-036)で管理者だけが変更できます。未設定のときは manual です。X の API キーを bot に用意してから api に切り替えてください。
kind | 対象 | 用途 |
|---|---|---|
daily_pre | 日別記事 | 示唆考察の告知 |
daily_after | 日別記事 | 結果考察の告知 |
paid_update | 有料記事 | 有料記事の公開・更新告知 |
1 ユーザーあたり GET は 1 分 120 回、記録は 1 分 20 回までです。超えると 429 になるので、1 件ずつループで叩かず一覧の Tool を使ってください。
REST の例(curl)
bash
SITE=https://example.com
AUTH='x-announce-bot:xxxx xxxx xxxx xxxx xxxx xxxx'
# 考察日の期間の公開済み日別記事
curl -sS -u "$AUTH" "$SITE/wp-json/x-announce/v1/daily-articles?date_from=2026-10-01&date_to=2026-10-03"
# 指定日時より後に更新された公開済み有料記事
curl -sS -u "$AUTH" "$SITE/wp-json/x-announce/v1/paid-articles?modified_after=2026-10-01T00:00:00Z"
# X への投稿方法(api / manual)
curl -sS -u "$AUTH" "$SITE/wp-json/x-announce/v1/settings"
# 告知履歴の記録
curl -sS -u "$AUTH" -H 'Content-Type: application/json' \
-d '{"post_id":123,"kind":"daily_pre","tweet_id":"1840000000000000000","posted_at":"2026-10-03T09:00:00+09:00"}' \
"$SITE/wp-json/x-announce/v1/announcements"トラブルシューティング
| 症状 | 確認 |
|---|---|
WP_SITE_URL / X_ANNOUNCE_WP_USERNAME / ... を設定 | .cursor/mcp.json の x-announce-tools.env |
HTTP 401(incorrect_password / invalid_username) | ユーザー名・アプリケーションパスワードの誤り、取り消し済み、HTTP サイトでの利用 |
HTTP 403(rest_forbidden、権限がありません) | 認証ヘッダーが PHP に届いていない、または権限グループが「X告知担当」でない・ADM-035 で「告知用メタ情報の取得」「告知履歴の記録」が外されている |
| HTTP 404(記事が見つかりません) | 記事が公開済みでない、または kind と投稿タイプが合っていない(daily_* に有料記事の ID を渡した等) |
| HTTP 429 | GET 1 分 120 回・記録 1 分 20 回を超えた。1 分待つ |
| HTTP 503(告知履歴を保存できませんでした) | DB 書き込みの一時的な失敗。時間をおいて同じ内容で再送する |
リダイレクトされました | 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-x-announce-tools.mjs(テスト:npm run test:mcp-x-announce。npm testにも含まれる) - 期間の上限 31 日は
XAnnounceRestController::MAX_RANGE_DAYSと同期する - 権限判定とレート制限は REST 側(
WordPressXAnnouncePermissionChecker)。MCP 側では判定しない