X MCPでAI/E2Eのトピックを毎朝Discordに流すBotを作った話

やりたかったこと
AI開発ツールやE2Eテスト自動化まわりは動きが早くて、ちょっと目を離すと何か出ています。 便利なんですが、これを毎日Xで追いかけるのがだんだん面倒になってきました。 毎朝Xを開いて検索して、ノイズの多い投稿をかき分けながら見るのは、けっこう疲れるんですよね。
そこで、X MCPを使って関連トピックを1日1回だけ拾ってきて、Discordに1枚のEmbedとして流すBotを作りました。
目的はかなり単純です。
- AI開発ツールの新しい話題を拾う
- E2Eテスト自動化の話題も拾う
- 毎朝Discordを見るだけでざっくり把握できるようにする
- なるべく低コストで運用する
- 空振りやエラーのときに無駄な投稿をしない
完成形としては、毎朝8時に AI / E2E X Topic Watch という投稿がDiscordに流れてくる、という感じです。
作ったもの
Node.js + TypeScriptで、常駐サーバー上で動くDiscord Botを作りました。
Bot自体はずっと常駐していて、X検索からDiscordへの投稿までの一連の処理だけをcronで毎朝起動する形です。 そのダイジェスト処理の流れはこんな感じ。
- cronで毎朝、ダイジェスト処理を起動する
- X MCPへ検索クエリを投げる
- 返ってきたstory(X/Grokがまとめた要約)/postを正規化する
- 関連度の低いものや検索汚染っぽいものを落とす
- 古い話題を鮮度フィルタで落とす
- AI開発ツール / E2Eテスト自動化 / MCP系に分類する
- Discord Embedとして投稿する
手動実行用に /digest-now も用意しています。
成功時の一時メッセージは数秒で消すようにして、Discord上に余計な表示が残らないようにしました。
構成
主な構成はこんな感じ。
- Runtime: Node.js
- Language: TypeScript
- Discord: discord.js
- Scheduler: node-cron
- X連携: X MCP +
@xdevplatform/xurl - 常駐: Ubuntu + systemd
X MCPへの接続は、xurl のMCP bridgeを経由しています。
npx -y @xdevplatform/xurl mcp https://api.x.com/mcp初回だけOAuth認証が必要なので、サーバー側では次を実行します。
npm run x:authUbuntuサーバーはCLI環境なので、表示されたURLを手元のWindowsブラウザで開いて認可しました。 この運用でも問題なく通りましたよ。
検索対象
最初はAI関連を全般的に拾おうとしていたのですが、これがまあノイズの多いこと。
そのへんの話は後の「検索汚染への対応」でまとめて書くとして、結論だけ言うと、目的に対してあまり意味のない投稿が混ざりまくったので、今はかなり開発寄りに絞っています。
AI開発ツール側では、主にこのあたりを見ています。
- Claude Code
- OpenAI Codex
- Cursor
- GitHub Copilot
- Devin
- Windsurf
- Replit
- Lovable
- Bolt
- v0
- MCP
E2Eテスト自動化側は、このへんを対象にしています。
- Playwright
- Cypress
- Selenium
- WebdriverIO
- BrowserStack
- QA Wolf
- Autify
- mabl
- MagicPod
- Momentic
実際のクエリは config/topics.ts にまとめてあります。
対象を増やしたくなったら、ここをいじる形ですね。
とにかく低コストで
今回いちばん気にしたのはコストです。
X API側のクレジットを消費するので、デバッグのために何度も /digest-now を叩くと、普通にお金が減っていきます。
最初はエラー調査のたびに再実行していたのですが、これはかなりよくない運用でした…。
今の本番設定は、だいたいこんな感じにしています。
GROK_ENABLED=false
X_SEARCH_QUERY_LIMIT=6X_SEARCH_MAX_RESULTS=5X_ENABLE_TRENDS=falseX_ENABLE_NEWS=falseTOPIC_FRESHNESS_HOURS=24
DAILY_CRON=0 8 * * *TZ=Asia/TokyoPOST_FAILURES_TO_DISCORD=falseX_SEARCH_QUERY_LIMIT=6、X_SEARCH_MAX_RESULTS=5 なので、1回あたり最大30件くらいを見に行く想定です。
1日1回だけなら、かなり控えめな設定かなと思います。
GROK_ENABLED=false にしているのもコストが理由です。
Grokに要約させると文章は自然になるんですが、今の目的だと元データの品質のほうが大事なので、まずはルールベースの整形だけで運用しています。
X_ENABLE_NEWS=falseでもstoryが返る
ちょっとややこしかったのが、X_ENABLE_NEWS=false の扱いです。
この設定は「追加のnews取得をするかどうか」を切り替えるものなんですが、X MCP側に search_news という検索ツールがある場合、通常の検索クエリでも search_news のほうが選ばれることがあります。
つまり、X_ENABLE_NEWS=false でも、検索結果としてX/Grokのstory要約が返ってくることがあるわけです。
最初はここを勘違いしやすかったのですが、今のBotはこの挙動を前提にしています。 投稿そのもののURLがない場合は、元投稿リンクではなく「この話題をXで検索」という検索リンクを出すようにしました。
デバッグ用にraw payloadを保存する
今回かなり効いたのが、raw responseの保存です。
X MCPの返り値は、検索ツールやタイミングによって形がころころ変わります。 投稿本文が返ることもあれば、story要約が返ることもあるし、エラー時にはJSON文字列としてエラーが返ってくることもありました。
そこで、1回だけ有料のX MCP呼び出しをして、その結果をファイルに保存できるようにしました。
DEBUG_SAVE_RAW_PAYLOADS=trueDEBUG_RAW_PAYLOAD_FILE=data/debug/latest-raw-items.json保存しておけば、次のようにするとX APIを呼ばずに同じデータで再生成できます。
REPLAY_RAW_PAYLOAD_FILE=data/debug/latest-raw-items.jsonこのリプレイモードを入れたおかげで、表示ロジックやフィルタ調整を無料で試し放題になりました。 これは最初から入れておけばよかったやつです。
表示の調整
最初の出力は、正直あんまり役に立ちませんでした。
特に微妙だったのがこのあたり。
- 主要アカウントの反応が空欄のまま残る
- 検索対象のキーワードをランキング表示しているだけになる
- 詳細リンクに見えるけど、実際は元投稿ではなくX検索リンク
ほかにも「投稿本文のつもりがstory要約だった」「エラーJSONがそのまま出た」あたりが地味につらかったのですが、これは後の「苦労した点」でまとめて書きます。
ということで、表示方針をけっこう変えました。
今は「投稿まとめ」ではなく「トピックウォッチ」として扱っています。
Embed内の主なセクションはこんな構成です。
- トレンド概要
- AI開発ツール
- E2Eテスト自動化
- MCP / エージェント基盤
E2Eの有効トピックが取れなかった日は、何も出さずに黙るのではなく「直近の取得範囲では見つかりませんでした」と出すようにしました。 地味ですが、毎日見るものとしてはここがかなり大事だと思っています。
表示されていないのか、取得できなかったのか、単に話題がなかったのかが分からないと、なんか不安になるんですよね。
検索汚染への対応
AI関連の検索は、本当にノイズが多いです。
単に AI や ChatGPT で検索すると、開発者向けじゃないものが大量に混ざってきます。
いわゆるAI驚き屋っぽい投稿、情報商材っぽい投稿、ChatGPTの呼び方の話、画像生成で遊んでみた系の話題…このあたりが目的に対してほぼ無意味で、なかなかしんどい。
今回ほしいのはAI一般ニュースではなく、AI開発ツールとE2Eテスト自動化の動向なので、要らないものはかなり落とすようにしました。
例えば、このへんは除外寄りにしています。
- 副業・収益化・情報商材っぽい話
- AIイラストや画像生成の遊び
- ChatGPTの呼び方の話
- バズや炎上そのものが中心の話
- E2E検索で拾ったのにE2Eの文脈がない話
逆に残す条件としては、ツール名だけじゃなくて、実装・開発・CI・テスト・API・GitHub・CLIあたりの文脈があるかを見ています。
このへんは完璧ではないです。 ただ、何でもかんでも拾うよりはだいぶマシになりました。
鮮度フィルタ
毎朝見るものなので、古い話題が何日も居座るのは微妙です。
そこで TOPIC_FRESHNESS_HOURS を入れて、今は24時間以内の話題だけを表示するようにしています。
TOPIC_FRESHNESS_HOURS=24ただし、X MCPのstory要約は更新時刻ベースになることがあって、良い話題でも24時間をちょっと超えると落ちてしまうことがあります。 空振りが多いようなら、ここを48時間に戻すのが現実的かなと思います。
このあたりは、速報性と空振り率のトレードオフですね。
systemdで常駐
サーバーではsystemdで常駐させています。
更新時はだいたいこの流れ。
cd /opt/x-mcpgit pullnpm installnpm run buildsudo systemctl restart x-mcp-digest-botsudo journalctl -u x-mcp-digest-bot -n 100 --no-pagerログには、どのツールを使ったか、何件正規化できたか、何件フィルタで残ったかを出しています。
例えばこんな情報が出ます。
[digest] rawItems=6 mode=live[digest] qualityFilter kept=7 dropped=16[digest] normalizedPosts=23 relevantPosts=7 freshPosts=4 freshnessHours=24rawItems が6なのに normalizedPosts が23に増えているのは、story要約1件の中に複数の投稿がぶら下がっていて、それを展開して数えているためです。
このログがあると、「X APIが失敗しているのか」「正規化で落ちているのか」「品質フィルタで落ちているのか」「鮮度フィルタで落ちているのか」が一目で分かるので便利です。
苦労した点
X MCPの返り値が思ったより一定じゃない
最初は「投稿検索だから投稿本文が返ってくるだろう」と思っていました。
ところが実際には、X/Grokのstory要約が返ってくることがあって、そこには元投稿URLや投稿者情報がない場合があります。
そのせいで、最初に作った「重要投稿」という表示はかなりズレていました。 今は「トピック」として扱って、リンクも元投稿ではなくX検索リンクなんだと分かる文言にしています。
エラーも投稿っぽく見えてしまった
クレジット不足のとき、{"detail":"credits depleted" ...} みたいなエラーJSONが、そのまま「重要投稿」として表示されてしまいました。
さすがにこれはよろしくないので、X APIのエラーpayloadを検出して、通常のトピックとしては扱わないようにしました。
クレジット不足の場合は、Botが壊れたわけではなく「X API側のクレジットが足りていない」と分かるメッセージを出すようにしています。
再実行がそのままコストになる
調整中に一番気をつけないといけないのがここでした。
表示が微妙だからといって何度も /digest-now を実行すると、そのたびにX APIを呼びます。要するに、直すたびにお金が飛ぶ。
調査にはraw payload保存とリプレイが必須でした。
やってよかった点
一番よかったのは、毎朝見る場所がDiscordにまとまったことです。
Xを開くと、ついそのまま別の投稿を延々と見続けてしまいがちなんですが、Discordに1枚だけ流れてくる形なら、必要な話題だけを軽く確認して終われます。
あと、E2Eテスト自動化の話題をAI開発ツールと同じ場所に流せるのも地味に便利です。 この2つは直接同じカテゴリというわけではないんですが、開発フロー改善という意味では一緒に見たいことが多いんですよね。
それと、低コスト前提で作ったので、運用し続ける心理的な負担が小さいです。 個人運用だと、ここがかなり大事だと思っています。
今後
今の状態で、ひとまず目的は達成できています。
今後いじるなら、このあたりを少しずつ良くしていきたいかなと。
- 検索クエリの見直し
- E2E側の話題が少なすぎる日の扱い
- 除外ルールの調整
- story要約ではなく投稿本文を拾うモードとの比較
- コスト上限に応じた安全設定
- Discord Embedの見やすさ改善
特にE2Eテスト自動化は、X上の話題量がAI開発ツールほど多くないので、24時間縛りだと空振りしやすいかもしれません。 その場合は、E2Eだけ48時間にするとか、カテゴリ別の鮮度設定を入れてもよさそうです。そのうちねw
おわりに
X MCPを使って、AI開発ツールとE2Eテスト自動化の話題を毎朝Discordに流すBotを作りました。
作ってみて分かったのは、検索そのものよりも、ノイズを落とすことと、取れたものを正直に表示することのほうがずっと大事だ、ということでした。 元投稿URLが取れないなら元投稿リンクっぽく見せない、E2Eの話題が取れないなら黙って消さない、エラーJSONを投稿として扱わない、デバッグではAPIを何度も叩かない。このへんを地道に直していって、ようやく毎日見てもいいかなという形になりました。
精度はまだまだ完璧とは言えませんが、個人で毎朝ざっくり技術トピックを追う用途としては、十分使えそうです。
次に読む
古い記事
自分専用に魔改造したBMSプレイヤー beatoraja の話
シリーズ一覧
すべて見るこのシリーズ情報は未設定です。シリーズ一覧ページから他の連載を探せます。