X (Twitter) について
mcp-xは、X API v2を通じてXアカウントの読み取り、検索、管理を行うGo製MCPサーバーです。42種類のツールがあり、OAuth 1.0aのユーザーコンテキストで、認証情報に対応するアカウントとして操作します。
主な機能
- 01最近の投稿の検索と集計
- 02タイムライン、メンション、ブックマークの読み取り
- 03ユーザーとリストの管理
- 04投稿、いいね、リポスト
- 05メディアのアップロードと添付
活用シーン
- 01複数のクエリで最近の投稿を検索
- 02アカウントのタイムラインとブックマークを確認
- 03アカウントとして投稿やリアクションを実行
MCP 対応
MCP対応クライアントにX API v2の42種類のツールを提供します。stdioとストリーミングHTTPのトランスポートに対応しています。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
mcp-x
LLM に X(Twitter)API を提供する MCP サーバーです。投稿の読み取りや検索、ユーザーやリストの管理、メディアのアップロード、投稿の公開を行えます。実行時に使用するキーに紐づくアカウントとして操作します。
ウェブサイト · 料金 · 認証情報 · ツール · クイックスタート · 設定 · アーキテクチャ · コントリビューション
概要
mcp-x は、Go で記述された Model Context Protocol サーバーです。X API v2 を、MCP 互換クライアント(Claude Desktop、IDE エージェント、カスタム LLM アプリ)に、投稿、ユーザー、リスト、メディアを扱う 42 個のツールとして提供します。
OAuth 1.0a ユーザーコンテキストで認証するため、すべての呼び出しは 実際の X アカウント、つまり 4 つのキーが属するアカウントとして実行されます。x_post_create は公開投稿を行います。x_user_follow は実際にフォローします。x_post_delete は取り消せません。これはサンドボックスではなく、無料でもありません。エージェントに接続する前に、X API は有料ですをご確認ください。
MCP SDK がサポートする両方のトランスポートを利用でき、どちらも同じツールセットを提供します。
- stdio — クライアントがバイナリを起動し、stdin/stdout 経由で通信します(デフォルト。デスクトップクライアントに最適です)。
- http — 長時間稼働するストリーミング HTTP サーバーです(リモート環境や共有環境へのデプロイに便利です)。
X API の利用には料金がかかります
警告
無料プランはもうありません。 X は新規開発者向けの Free/Basic/Pro サブスクリプションプランを廃止し、従量課金制クレジットに移行しました。Developer Console で事前にクレジットを購入し、リクエストごとに残高からリアルタイムで差し引かれます。従来の Basic(月額 $200)と Pro(月額 $5,000)は、すでに契約していたアカウントでのみ引き続き利用できます。Enterprise は月額約 $42,000 からです。現在、新しく開発者アカウントを作成すると、従量課金制のみが適用されます。
執筆時点の料金です(公式料金 — 2026 年に何度か変更されているため、必ず Console で再確認してください)。
| 操作 | 料金 |
|---|---|
| 投稿の読み取り | 返された投稿 1 件あたり $0.005 |
| 自分のリソースの読み取り(自分の投稿、ブックマーク、フォロワー、「いいね」、リスト) | リソース 1 件あたり $0.001 |
| ユーザーの読み取り | 返されたユーザー 1 人あたり $0.010 |
| 「いいね」/ミュート/ブロックの読み取り | リソース 1 件あたり $0.001 |
| フォロワー/フォロー中のアカウントの読み取り | リソース 1 件あたり $0.010 |
| 投稿の公開 | リクエスト 1 回あたり $0.015 |
| URL を含む投稿の公開 | リクエスト 1 回あたり $0.200 |
| 「いいね」/リポストなどのインタラクション | リクエスト 1 回あたり $0.015 |
| リストとブックマークへの書き込み | リクエスト 1 回あたり $0.005~$0.010 |
このことから、次の 2 点が導かれます。どちらもサーバーに組み込まれています。
- 読み取りの料金は、リクエストごとではなく、返された リソースごと に発生します。 同じクエリで
x_posts_searchのmax_results: 100を指定すると、max_results: 5を指定した場合の 20 倍の料金がかかります。すべての読み取りツールの説明では、質問に答えるのに必要な最小のmax_resultsを指定するようモデルに指示しています。また、バッチ処理ツール(x_posts_lookup、x_users_lookup)では、繰り返し処理するのではなく、まとめて処理するよう指示しています。 x_posts_countは投稿読み取りの予算を消費しません。 同じクエリ構文で、分/時間/日ごとに分類した一致件数を返します。まずx_posts_countでトピックの規模を把握してから、x_posts_searchの料金を支払ってください。
X は重複排除も行います。UTC の 24 時間以内に同じリソースを 2 回取得しても、料金が発生するのは 1 回です。また、従量課金制では、請求サイクルあたりの投稿読み取り数が 300 万件に制限されています。それを超えた場合は、Enterprise のみ利用できます。
料金を使い切ると、API は専用のエラーを返します。サーバーはそれを、モデルに再試行しないよう明示するメッセージに変換します。詳しくはエラーを参照してください。
認証情報
サーバーには、1 つの X アプリから取得した OAuth 1.0a の値が4 つ必要です。
X_API_KEY
X_API_KEY_SECRET
X_ACCESS_TOKEN
X_ACCESS_TOKEN_SECRET
最初のペアは アプリ を識別し、2 番目のペアはそのアプリを通じて操作する アカウント を識別します。mcp-x が AuthenMethodOAuth1UserContext を使用し、アプリ専用のベアラー認証を使用しないのは、すべての書き込みエンドポイントとすべての「自分」に関するエンドポイント(x_users_me、x_posts_home、x_bookmarks_list、メンション)でユーザーコンテキストが必要になるためです。ベアラートークンモードはありません。
認証情報の取得方法 — 誰もが間違える 1 つの手順
- developer.x.com に移動し、プロジェクトからアプリを開きます。
- User authentication settings を開き、App permissions を Read and Write に設定します。必ず最初に行ってください。
- その後でのみ、Keys and tokens に移動し、Access Token and Secret を生成します。
重要
アクセストークンには、生成時点でアプリに設定されていた権限が固定されます。 アプリが Read-only のときにトークンを作成し、その後アプリの権限を Read and Write に変更しても、トークンは 読み取り専用のまま です。アプリ設定ページを見ても、このことはわかりません。Keys and tokens に戻って Access Token and Secret を再生成するまで、すべての書き込みは X の
oauth1-permissions問題タイプで失敗し続けます。これは X API で最もよくある設定ミスです。そのため、サーバーは起動時にチェックし、次のメッセージを表示して起動を拒否します。
the access token is read-only: set the app permissions to Read and Write in the X Developer Console, then regenerate the Access Token and SecretAPI Key/Secret の再生成では解決しません。Access Token and Secret を再生成してください。
起動時の検証
ツールを1つでも登録する前に、サーバーは15秒の期限内にGET /2/users/meを1回呼び出します(client.Bootstrap)。これには3つの役割があります。
- 4つのキーが有効であることを確認します。不正なキーがある場合は、最初のツール呼び出しではなくプロセスが失敗します。
- 上記の読み取り専用トークンの落とし穴を検出します。
- キー所有者の数値のユーザーIDをキャッシュします。すべての書き込みエンドポイントは
POST /2/users/:id/...であり、書き込みのたびにIDを調べると、別途課金対象のリクエストが必要になるためです。
ここでの失敗は、意図的に致命的なものとして扱われます。起動した後ですべての呼び出しに失敗するサーバーより、起動しないサーバーのほうがましです。
この選択に伴うコストは、はっきり述べておく必要があります。**資金があるX開発者アカウントがなければ、このサーバーを試す方法はありません。**認証情報がなければ起動できず、ツール一覧も表示されません。/mcpとclaude mcp listには、接続失敗とだけ表示されます。それ以外の方法でインストールを確認するには、バイナリを-version付きで実行し、公開されるツールについてはツールのセクションを確認してください。
キーは秘密情報です
4つの値は、書き込みアクセス権を持つ有効なアカウントの認証情報です。自分だけが読み取れるファイルに保管し、-envで指定してください。また、決してコミットしないでください。.envはgitignoreの対象で、.env.exampleはテンプレートです。MCPクライアントで実行する場合は、クライアントのenvブロックも使用できます。この設定は.envファイルより優先されます。
ツール
4つのグループに42個のツールがあります。各ツールにはMCPアノテーションが付いています。読み取り操作にはreadOnlyHint、取り消せない操作(x_post_delete、x_list_delete、いいねの取り消し、リポストの取り消し、フォロー解除、メンバーの削除)にはdestructiveHintが付いています。各ツールは出力スキーマに一致する構造化JSONペイロードを返します。SDKは同じJSONをテキストコンテンツブロックにも反映するため、structuredContentを読み取らないクライアントでも利用できます。
すべてのツールでtimeout_msを任意に指定できます。値はグループごとの[MIN, MAX]の範囲に収まるよう調整されます(制限を参照)。
投稿 — 読み取り
| ツール | 説明 |
|---|---|
x_posts_search | 複数のクエリについて、最近の投稿を並列で検索します。最近の投稿の検索対象は、さかのぼって7日間のみです。 |
x_posts_count | クエリごとの一致件数を、分・時間・日単位で集計します。投稿の読み取り回数を消費しません。検索前にトピックの規模を把握するために使います。 |
x_posts_lookup | 1回の呼び出しで、IDを指定して最大100件の投稿を取得します。 |
x_posts_by_user | 複数のユーザー名について、最近の投稿を並列で取得します。 |
x_posts_mentions | キー所有者にメンションした投稿です。 |
x_posts_home | キー所有者のホームタイムラインです。 |
x_posts_quotes | 指定した投稿を引用している投稿です。 |
x_posts_liked | キー所有者がいいねした投稿です。 |
x_bookmarks_list | キー所有者のブックマークです。 |
x_post_liked_by | 指定した投稿にいいねしたユーザーです。 |
x_post_reposted_by | 指定した投稿をリポストしたユーザーです。 |
x_posts_search
| パラメーター | 型 | デフォルト | 備考 |
|---|---|---|---|
queries | []string | — | **必須。**並列で実行します。上限はPOSTS_MAX_QUERIES(5)です。各クエリは512文字以下です。 |
max_results | int | 10 | クエリごとの投稿数です。1~100件。1件ごとに課金されます。 |
sort_order | string | — | recency(新しい順)またはrelevancy(関連度順)です。 |
days | int | 7 | さかのぼる日数です。1~7日。APIはこれ以上さかのぼれません。 |
include_retweets | bool | false | falseの場合、サーバーはすべてのクエリに-is:retweetを追加します。 |
timeout_ms | int64 | 15000 | 呼び出し全体のタイムアウトです。[2000, 60000]の範囲に調整されます。 |
クエリ演算子はクエリ文字列内に記述します。
| 演算子 | 意味 |
|---|---|
| スペース | AND |
OR | 明示的なOR |
-term | NOT |
( ) | グループ化 |
from:user / to:user | 投稿者/宛先で指定 |
@user / #tag | メンション/ハッシュタグ |
"exact phrase" | 完全一致するフレーズ |
lang:en | 言語 |
is:retweet is:reply is:quote is:verified | 投稿の種類 |
has:media has:images has:videos has:links | 添付ファイル |
url:example.com | リンク先のドメイン |
conversation_id:123 | 1つのスレッド |
x_posts_count
| パラメーター | 型 | デフォルト | 備考 |
|---|---|---|---|
queries | []string | — | 必須。 x_posts_search と同じ演算子を使用します。 |
granularity | string | hour | minute、hour、day のいずれかです。 |
days | int | 7 | 1..7。同じ期間です。 |
timeout_ms | int64 | 15000 | [2000, 60000] の範囲に制限されます。 |
x_posts_lookup
| パラメーター | 型 | デフォルト | 備考 |
|---|---|---|---|
ids | []string | — | 必須。 投稿 ID を1..100個指定します。まとめて取得し、IDごとに呼び出さないでください。 |
x_posts_by_user
| パラメーター | 型 | デフォルト | 備考 |
|---|---|---|---|
usernames | []string | — | 必須。 @ は付けません。POSTS_MAX_USERNAMES(5)までに制限され、並列で取得されます。 |
max_results | int | 10 | ユーザーごとの投稿数。1..100です。 |
exclude | []string | — | replies および/または retweets。 |
days | int | 7 | 1..7です。 |
timeout_ms | int64 | 15000 | [2000, 60000] の範囲に制限されます。 |
タイムラインツール
x_posts_mentions、x_posts_home、x_posts_liked、x_bookmarks_list は、max_results(1..100)、pagination_token、timeout_ms という同じ形式です。x_posts_quotes、x_post_liked_by、x_post_reposted_by には、必須の id もあります。
ページネーションは明示的かつ手動で行います。レスポンスに next_token が含まれるため、次のページではそれを pagination_token として渡してください。サーバーが自動でページを取得することはありません。ページごとに課金されるため、取得するかどうかは呼び出し元が判断します。
投稿 — 書き込み
| ツール | 注釈 | 説明 |
|---|---|---|
x_post_create | 書き込み | 投稿を公開します。公開され、課金対象です($0.015、リンク付きの場合は$0.20)。 |
x_post_delete | 破壊的操作 | 自分の投稿を削除します。元に戻せません。 |
x_post_like / x_post_unlike | 書き込み/破壊的操作 | いいねは公開されます。 |
x_post_repost / x_post_unrepost | 書き込み/破壊的操作 | リポストは公開されます。 |
x_post_create
| パラメーター | 型 | 備考 |
|---|---|---|
text | string | 280文字以下です。media_ids が設定されていない場合は必須です。 |
reply_to_id | string | この投稿に返信します。 |
quote_id | string | この投稿を引用します。 |
media_ids | []string | x_media_upload で取得した ID を1..4個指定します。 |
poll | object | options(2..4)と duration_minutes(5..10080)を指定します。media_ids と併用できません。 |
reply_settings | string | following、mentionedUsers、subscribers、verified のいずれかです。 |
同じテキストを連続して2回公開しようとすると、重複投稿として X に拒否されます。サーバーはこれを一般的な失敗としてではなく、個別のメッセージとして返します。
ユーザー
| ツール | 注釈 | 説明 |
|---|---|---|
x_users_lookup | 読み取り | 1回の呼び出しでユーザー名を最大100個、または ID を最大100個取得できます。どちらか一方のみで、両方は指定できません。解決できなかった名前は not_found に返されます。 |
x_users_me | 読み取り | キーに紐づくプロフィールです。 |
x_user_followers / x_user_following | 読み取り | 1ページずつ取得します。max_results は最大1000です。 |
x_user_follow / x_user_unfollow | 書き込み/破壊的操作 | 公開されます。 |
x_user_mute / x_user_unmute | 書き込み | ミュートは相手に通知されません。相手は引き続きあなたを見ることができます。 |
x_users_muted / x_users_blocked | 読み取り | キー所有者がミュートまたはブロックしているアカウントです。 |
ブロックとブロック解除の操作は、意図的に公開していません。ブロックリストの読み取りは可能です。
リスト
| ツール | 注釈 | 説明 |
|---|---|---|
x_list_create | 書き込み | 名前は 25 文字以内、説明は 100 文字以内です。非公開リストを閲覧できるのは所有者のみです。 |
x_list_update | 書き込み | 変更するフィールドのみ送信してください。 |
x_list_delete | 破壊的操作 | 取り消しできません。リスト、メンバーシップ、フォロワーがすべて削除されます。 |
x_list_get | 読み取り | メンバー数とフォロワー数を含む、1 つのリストです。 |
x_lists_owned | 読み取り | ユーザー名で指定したアカウントが所有するリスト、または省略した場合はキー所有者が所有するリストです。 |
x_list_posts | 読み取り | リストのメンバーによる最近の投稿です。投稿ごとに課金されます。 |
x_list_members | 読み取り | リスト内のアカウントをページネーションで取得します。 |
x_list_member_add / x_list_member_remove | 書き込み / 破壊的操作 | ユーザー名で指定します。 |
x_list_follow / x_list_unfollow | 書き込み / 破壊的操作 | 公開リストのみです。 |
x_list_pin / x_list_unpin / x_lists_pinned | 書き込み / 書き込み / 読み取り | キー所有者がピン留めしたリストです。 |
メディア
x_media_upload
チャンク化された INIT → APPEND → FINALIZE フローを使用して画像、GIF、または動画をアップロードし、x_post_create 用の media_id を返します。
| パラメーター | 型 | 備考 |
|---|---|---|
path | string | ローカルファイルです。MEDIA_ROOT 内に置く必要があります。 |
base64 | string | パスの代わりにファイルの内容を指定します。mime が必要です。 |
mime | string | 例:image/jpeg、video/mp4。base64 と併せて指定する必要があります。 |
category | string | 必須です。 tweet_image(≤ 5 MB)、tweet_gif(≤ 15 MB)、tweet_video(≤ 512 MB)。 |
timeout_ms | int64 | デフォルトは 120000 で、[5000, 600000] の範囲に制限されます。アップロードと X のトランスコードの両方を対象とします。 |
知っておくべきことが 2 つあります。
MEDIA_ROOTは厳格な境界です。 デフォルト値がない必須設定であり、シンボリックリンクも含め、解決先がその外部になるパスはサーバーが拒否します。この設定がないと、このツールを持つ LLM がホスト上のあらゆるファイルを読み取り、投稿できてしまいます。専用のディレクトリを選んでください。- 動画は X によって非同期でトランスコードされます。 サーバーは
MEDIA_POLL_INTERVAL_MSごとに FINALIZE のステータスをポーリングしますが、エンコードに時間がかかるとstatus: "pending"が返ることがあります。media_idは有効ですが、まだ投稿には使用できません。少し待ってからx_post_createを再試行してください。media_idは一定時間後に期限切れとなり、単一の投稿に使用することを想定しています。
部分的な結果
ファンアウトツールである x_posts_search、x_posts_count、x_posts_by_user は、それぞれの入力を並列で実行し、クエリまたはユーザー名ごとに 1 つのエントリーを返します。各エントリーには独自の status が含まれるため、1 つの入力に問題があっても、正常に処理できた結果は失われません。x_posts_lookup も ID ごとに同様に処理し(not found は解決できた投稿と並んで表示されます)、x_users_lookup は解決できなかった名前を not_found にまとめます。
入力が処理開始前に拒否された場合、またはすべての項目で失敗した場合に限り、呼び出し全体が失敗します。
エラー
失敗は isError: true とプレーンテキストのメッセージを含むツールの結果として返され、JSON-RPC エラーとしては返されません。モデルはメッセージを読んで呼び出しを自分で修正できます。メッセージはログを読む人ではなくモデル向けに書かれているため、再試行してはならないものにはその旨が明記されています。
| メッセージ | 意味 |
|---|---|
the access token is read-only: …regenerate the Access Token and Secret | 読み取り専用トークンの罠です。 |
the monthly usage cap for this project is reached; …do not retry | 使用上限に達しました。リセットされるまで何も機能しません。 |
the project has no X API credits left; …do not retry | クレジットが枯渇しました。リセットされないため、コンソールで追加してください。 |
rate limit exceeded; the window resets in about 15 minutes | 間隔を空けてください。連続してリクエストを送らないでください。 |
X rejected the credentials; check the four keys | キーが無効か、取り消されています。 |
not authorized for this resource | 保護対象、削除済み、または他のユーザーのものです。 |
X rejected this as a duplicate of a recent post | テキストを変更してください。 |
user not found / post not found / list not found | 説明のとおりです。 |
X failed to process the uploaded media; re-encode the file | トランスコードに失敗しました。 |
media exceeds the size limit for its category | 5 MB / 15 MB / 512 MB です。 |
the path is outside the directory this server is allowed to read | MEDIA_ROOT 違反です。 |
post text exceeds 280 characters | — |
a post needs text unless it carries media | — |
a poll needs 2 to 4 options and a duration between 5 and 10080 minutes | — |
a post carries at most 4 media items | — |
too many ids in one call; the limit is 100 | — |
invalid username: 1 to 15 letters, digits or underscores | リクエストを消費する前に、ローカルで検証されます。 |
every query failed; the X API may be unreachable | すべての項目が失敗しました。 |
the call timed out; retry with a larger timeout_ms or fewer inputs | — |
the X API is unavailable | 5xx または分類されていない上流障害です。 |
分類は adapter/x/apierr で行われ、意図的に防御的な設計になっています。X は Content-Type: application/problem+json でエラーを返しますが、基盤となる gotwi クライアントはこれを JSON として認識しません。そのため、問題の本文全体が型付きフィールドにデコードされず、そのままメッセージフィールドに入ります。そこでマッパーは、レスポンスに含まれる可能性のあるすべての情報源を連結し、その文字列から問題タイプ(oauth1-permissions、usage-capped、credits-depleted、rate-limit-exceeded、…)を照合します。一致するものがなければ、HTTP ステータスコードを使います。
既知の制限事項
- 最近の検索のみです。 過去 7 日間に限られます。過去のアーカイブ検索は別の(Enterprise)製品であり、接続されていません。
- ブロック機能は公開されていません。
x_users_blockedはリストを読み取りますが、ブロック/ブロック解除ツールはありません。 - ストリーミングエンドポイントはありません。 フィルター付きストリームとサンプルストリームは実装されていません。
- DM はありません。
- 1 プロセスにつき 1 アカウントです。 キーはプロセス全体で共有され、キーの所有者は起動時に一度だけ特定されます。複数のアカウントに対応するには、複数のプロセスが必要です。
- ページネーションは手動です。 ツールは
next_tokenを返します。各ページに課金されるため、自動的にページをたどることはありません。
クイックスタート
インストール
用途に合うものを選んでください。どれを選んでも、同じサーバーを利用できます。
コンテナー(Go ツールチェーンは不要です):
docker pull ghcr.io/role1776/mcp-x:0.1.1 # or :latest to track the newest release
依存するものでは、明示的なバージョンを指定してください。:latest は安定版リリースのたびに更新され、リリースによってツールの動作が追加・変更される場合があります。server.json には、MCP Registry が告知するものと同じバージョンが指定されています。
ビルド済みバイナリ — お使いのプラットフォーム用のアーカイブを最新リリースからダウンロードして展開し、mcp-x を PATH に追加してください。
MCP Bundle — .mcpb ファイルをインストールできるクライアントの場合は、mcp-x_<version>_<os>_<arch>.mcpb を最新リリースからダウンロードし、クライアントで開いてください。バンドルにはコンパイル済みバイナリが含まれているため、Docker も Go も不要です。また、インストール時にクライアントが必須の 5 つの値を尋ねます。OS と CPU アーキテクチャの両方に一致するファイルを選んでください。バンドルにはネイティブバイナリが 1 つ含まれています。
メモ
v0.1.1 より前にビルドされたバンドルでは、設定項目が宣言されていなかったため、クライアントは認証情報を尋ねず、サーバーは起動するたびに終了していました。v0.1.1 以降を使用してください。
ソースから(Go 1.26 以降が必要です):
git clone https://github.com/Role1776/mcp-x
cd mcp-x
make build # -> bin/mcp-x
go install も使えますが、実行する前に知っておくべき注意点が 1 つあります。
go install github.com/Role1776/mcp-x/app/cmd/mcp-x@latest
Go モジュールは app/ にあるため、リリースタグ(v0.1.0)ではモジュールを指定できません。@v0.1.0 はそのまま失敗し、@latest は main 上の最新コミットの疑似バージョンに解決されます。また、go install でビルドした場合、バージョンは dev と報告されます。バージョンはモジュールではなく、リリースパイプラインで設定されるためです。リリースと完全に一致するビルドを使うには、ビルド済みバイナリ、コンテナー、またはチェックアウトしたタグからの make build を使用してください。
設定
クローンしたリポジトリ、または展開したリリースアーカイブ(どちらにもテンプレートが含まれています)から:
cp .env.example .env
$EDITOR .env # fill in the four X_* keys and MEDIA_ROOT
コンテナーまたは .mcpb バンドルからインストールすると、コピー元のチェックアウトがありません。テンプレートは.env.exampleから取得するか、ファイルを使わずに、クライアントの env ブロック(以下を参照)に 5 つの値を渡してください。
5 つの値が必須で、それ以外はすべてデフォルト値があります。MEDIA_ROOT には、すでに存在するディレクトリの絶対パスを指定してください。サーバーは起動時にこれを確認し、指定が正しくない場合は、最初のアップロード時に失敗するのではなく、起動を拒否します。
実行
./bin/mcp-x -env /absolute/path/to/.env
| フラグ | 説明 |
|---|---|
-version | バイナリが MCP クライアントに報告するバージョンを表示して終了します。ハンドシェイクとは異なり、認証情報がなくても応答できます。 |
-env | .env ファイルへのパスです。暗黙的な検索は行われません — stdio では作業ディレクトリが MCP クライアントによって決定されるため、相対パスのデフォルト値は予測できません。このフラグを省略した場合、またはファイルが存在しない場合、サーバーは環境変数にフォールバックし、その旨を stderr に出力します。起動には、必須の 5 つの値をどこかで設定しておく必要があります。設定されていない場合、起動に失敗します。 |
起動に成功すると、認証済みアカウントがログに出力されます。
INFO authenticated with the X API op=app.Run user_id=1234567890
INFO MCP server has started op=app.Run transport=stdio
MCP クライアントへの接続(stdio)
Claude Code — 認証情報をインラインで指定して 1 つのコマンドで実行します(-- はサーバー自身のコマンドと、その前に指定するフラグを区切ります)。
claude mcp add mcp-x \
-e X_API_KEY=... \
-e X_API_KEY_SECRET=... \
-e X_ACCESS_TOKEN=... \
-e X_ACCESS_TOKEN_SECRET=... \
-e MEDIA_ROOT=/absolute/path/to/media \
-- /absolute/path/to/mcp-x
代わりに .env ファイルを指定することもできます:-- /absolute/path/to/mcp-x -env /absolute/path/to/.env。claude mcp list、またはセッション内で /mcp を実行して結果を確認してください。
Claude Desktop などの JSON 設定を使用するクライアント — ビルド済みバイナリを指定します。
{
"mcpServers": {
"x": {
"command": "/absolute/path/to/mcp-x",
"args": ["-env", "/absolute/path/to/.env"]
}
}
}
ファイルを使わずに、認証情報を env ブロックで渡すこともできます。環境変数は .env ファイルより優先されるため、クライアントの env ブロックの値が常に適用されます。
{
"mcpServers": {
"x": {
"command": "/absolute/path/to/mcp-x",
"env": {
"X_API_KEY": "...",
"X_API_KEY_SECRET": "...",
"X_ACCESS_TOKEN": "...",
"X_ACCESS_TOKEN_SECRET": "...",
"MEDIA_ROOT": "/absolute/path/to/media"
}
}
}
}
MCP クライアントの接続(コンテナ)
イメージを stdio で実行します。Docker では、各変数がプロセスに渡るよう、コマンドラインで -e を付けて指定する必要があります。また、MEDIA_ROOT が意味を持つのは、ディレクトリをマウントした場合のみです。
{
"mcpServers": {
"x": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "X_API_KEY",
"-e", "X_API_KEY_SECRET",
"-e", "X_ACCESS_TOKEN",
"-e", "X_ACCESS_TOKEN_SECRET",
"-e", "MEDIA_ROOT",
"-v", "/host/media:/media:ro",
"ghcr.io/role1776/mcp-x:0.1.1"
],
"env": {
"X_API_KEY": "...",
"X_API_KEY_SECRET": "...",
"X_ACCESS_TOKEN": "...",
"X_ACCESS_TOKEN_SECRET": "...",
"MEDIA_ROOT": "/media"
}
}
}
}
-i は必須です。これを指定しないとコンテナに stdin が渡されず、クライアントにはサーバーがすぐに終了したように見えます。* MCP Registry 自体から*インストールするクライアントは、この呼び出しを自動で構成し、server.json で宣言された変数の入力を求めます。これはクライアント側の機能であり、このサーバーと通信できるすべてのクライアントに当てはまるわけではありません。たとえば Claude Code の CLI はレジストリからインストールしないため、上記の claude mcp add を使用してください。
クライアントに接続が切れたと表示される場合
stdio では、サーバーの stderr はクライアント側のものであり、ほとんどのクライアントはこれを破棄します。そのため、サーバーが問題を一行で明確に説明していても、こちらには次のようにしか表示されません。
✘ Failed to connect — -32000: Connection closed
同じ環境変数を設定してバイナリを手動実行し、実際の原因を確認してください。
/absolute/path/to/mcp-x -env /absolute/path/to/.env
何が問題なのかを正確に出力して終了します。どの変数が不足しているかとその入手先、キーが拒否されたこと、またはアクセストークンが読み取り専用であることが示されます。インストールの失敗は、ほぼすべてこの3つのいずれかが原因です。
HTTP で実行する
MCP_TRANSPORT=http を設定すると、サーバーは MCP_PATH(デフォルトは http://localhost:8080/mcp)で SERVER_PORT をリッスンします。
注意
HTTP トランスポートには独自の認証機能がありません。エンドポイントにアクセスできる人は誰でも、あなたのアカウントとして、あなたのクレジットを使って公開、削除、フォローを実行できます。localhost にバインドするか、認証機能のあるリバースプロキシの背後に配置してください。インターネットに直接公開しないでください。
設定
すべて環境変数で設定し、各値は起動前に検証されます。必須キーが欠けている場合、または数値以外や正の数でない値が設定されている場合は、実際に設定した変数名(APIKey ではなく X_API_KEY)を示す起動エラーになります。上限値どうしの関係は起動時に検証されません。上限値を参照してください。環境にすでに存在する変数は、.env ファイルより優先されます。
デフォルト値を設定した完全な一覧は .env.example を参照してください。コピーして .env として使用できます。
必須
| 環境変数 | 備考 |
|---|---|
X_API_KEY | OAuth 1.0a のコンシューマーキーです。 |
X_API_KEY_SECRET | OAuth 1.0a のコンシューマーシークレットです。 |
X_ACCESS_TOKEN | ユーザーアクセストークンです。読み取りと書き込みを設定した後に生成してください。 |
X_ACCESS_TOKEN_SECRET | ユーザーアクセストークンシークレットです。 |
MEDIA_ROOT | x_media_upload が読み取り可能な唯一のディレクトリの絶対パスです。存在し、ディレクトリである必要があります。どちらも起動時に確認されます。意図的にデフォルト値はありません。 |
いずれかが不足している場合、不足している項目の一覧と Developer Console への案内を表示して起動を中止します。
MCP サーバー
| 環境変数 | デフォルト | 備考 |
|---|---|---|
MCP_TRANSPORT | stdio | stdio または http です。 |
MCP_NAME | mcp-x | クライアントに通知されるサーバー名です。 |
MCP_PATH | /mcp | HTTP ルートです(http トランスポートのみ)。 |
クライアントに通知されるバージョンは設定できません。ビルド時に git タグからバイナリに埋め込まれます。
HTTP サーバー(http トランスポートのみ)
| 環境変数 | デフォルト |
|---|---|
SERVER_PORT | 8080 |
SERVER_READ_TIMEOUT | 60s |
SERVER_WRITE_TIMEOUT | 60s |
HTTP クライアント
| 環境変数 | デフォルト | 備考 |
|---|---|---|
MAX_IDLE_CONNS_PER_HOST | 100 | X API へのコネクションプーリングです。 |
X_DEBUG | false | 生の gotwi リクエストをログに記録します。詳細なログですが、X のエラーの意味がわからない場合に役立ちます。 |
ロギング
| 環境変数 | デフォルト | 備考 |
|---|---|---|
LOG_MODE | local | local → デバッグレベルのテキストハンドラー、prod → 情報レベルの JSON ハンドラーです。ログは stderr に出力されます(MCP プロトコルが stdout を使用するため、必ずそうする必要があります)。 |
制限
グループごとに独自の制限があるため、メディアのアップロードが遅くても、検索タイムアウトによって上限が設定されることはありません。
投稿
| 環境変数 | デフォルト | 備考 |
|---|---|---|
POSTS_MAX_QUERIES | 5 | x_posts_search/x_posts_count 呼び出しあたりのクエリ数です。 |
POSTS_MAX_USERNAMES | 5 | x_posts_by_user 呼び出しあたりのユーザー名数です。 |
POSTS_MAX_IDS | 100 | x_posts_lookup あたりの ID 数です。API 独自の上限です。 |
POSTS_DEFAULT_RESULTS | 10 | |
POSTS_MAX_RESULTS | 100 | |
POSTS_DEFAULT_DAYS | 7 | |
POSTS_MAX_DAYS | 7 | 最近の検索では、これより過去にさかのぼることはできません。 |
POSTS_DEFAULT_TIMEOUT_MS | 15000 | |
POSTS_MIN_TIMEOUT_MS | 2000 | |
POSTS_MAX_TIMEOUT_MS | 60000 |
ユーザー
| 環境変数 | デフォルト |
|---|---|
USERS_MAX_USERNAMES | 100 |
USERS_MAX_IDS | 100 |
USERS_DEFAULT_RESULTS | 100 |
USERS_MAX_RESULTS | 1000 |
USERS_DEFAULT_TIMEOUT_MS | 15000 |
USERS_MIN_TIMEOUT_MS | 2000 |
USERS_MAX_TIMEOUT_MS | 60000 |
リスト
| 環境変数 | デフォルト |
|---|---|
LISTS_DEFAULT_RESULTS | 25 |
LISTS_MAX_RESULTS | 100 |
LISTS_DEFAULT_TIMEOUT_MS | 15000 |
LISTS_MIN_TIMEOUT_MS | 2000 |
LISTS_MAX_TIMEOUT_MS | 60000 |
メディア
| 環境変数 | デフォルト | 備考 |
|---|---|---|
MEDIA_CHUNK_BYTES | 4194304 | 4 MB です。APPEND エンドポイントでは、セグメントの上限は 5 MB です。 |
MEDIA_POLL_INTERVAL_MS | 2000 | X によるトランスコード中に FINALIZE のステータスをポーリングする間隔です。 |
MEDIA_DEFAULT_TIMEOUT_MS | 120000 | |
MEDIA_MIN_TIMEOUT_MS | 5000 | |
MEDIA_MAX_TIMEOUT_MS | 600000 | 大容量の動画向けの 10 分です。 |
各値は個別に検証され、ゼロより大きい値である必要があります。また、API 自体に上限がある値(*_MAX_IDS、POSTS_MAX_RESULTS、LISTS_MAX_RESULTS、POSTS_MAX_DAYS)は、誤入力によって X に拒否されるリクエストが発生しないよう、API の上限を超えない値にさらに制限されます。DEFAULT_*、MIN_*、MAX_* の組み合わせは、起動時に相互検証されません。整合性のない設定でもサーバーは停止せず、リクエストごとに調整されます。
- 呼び出し元が値を省略するか、ゼロまたは負の値を渡した場合、対応する
DEFAULT_*にフォールバックします。 - その後、値は
[MIN_*, MAX_*]の範囲内に制限されます。そのため、DEFAULT_*がMAX_*より大きい場合は、MAX_*が適用されます。 MIN_*がMAX_*を超える場合は、最大値が優先されます。
したがって、有効な制限は常に設定された最大値の範囲内となり、設定ミスがあっても起動に失敗するのではなく、動作するサーバーとして稼働します。その代わり、設定ミスが通知されずに処理されます。たとえば、POSTS_MAX_RESULTS=10 の代わりに POSTS_MAX_RESULTS=1 と設定しても警告は出ず、応答件数がひっそりと少なくなるだけです。結果が途中で切れているように見える場合は、これらの値を再確認してください。
アーキテクチャ
このプロジェクトは、クリーンな階層構造を採用しています。依存関係はドメインに向かい、各レイヤーはインターフェースを介して次のレイヤーと通信します。
app/ the Go module: sources plus its build files
(Dockerfile, .dockerignore, .goreleaser.yaml)
cmd/mcp-x/main.go entry point: parse flags, load config, run app
internal/
app/ wiring + lifecycle (X client, bootstrap, run, graceful shutdown)
config/ config loading (.env → env vars → validate → env-name error messages)
domain/x/ core types and errors
posts/ users/ lists/ media/ value objects: PostID, UserID, Username, Draft, Query, Upload…
format.go shared snowflake-id and username validation
errors.go the sentinel error set the whole app maps onto
dto/x/ request/response shapes for the MCP tools, with jsonschema + validate tags
transport/mcp/ MCP layer
router/ registers every tool group on the MCP server
x/posts|users|lists|media/ tool definitions, handlers and error → tool-result mapping
usecase/x/ business logic: validation, parallelism, timeouts, limit resolution
adapter/x/ X API wiring
client/ gotwi client + startup Bootstrap (key check, key-owner id)
apierr/ X problem responses → domain errors
posts|users|lists|media/ endpoint calls and mappers to DTOs
pkg/ reusable building blocks (mcpserver, server, logger, validator, parallel)
ツール呼び出しのリクエストフロー:
MCP client → transport/mcp/x/... (handler) → usecase/x/... → adapter/x/... → gotwi → X API
↑ maps errors ↑ validates, resolves limits,
to isError text fans out, applies timeouts
特に重要な境界が 2 つあります。
- ドメイン層では無効な値の生成が拒否されます。
NewPostID、NewUserID、NewUsername、NewDraftなどは生成時に検証されるため、不正な ID や 300 文字の投稿は、リクエストを消費する前にローカルで拒否されます。ID はスノーフレーク形式に照らして検証され、ユーザー名は X の 1~15 文字の[A-Za-z0-9_]というルールに照らして、共通のformatパッケージで検証されます。 - すべてのレイヤーで同じエラーの語彙が使われます。 アダプターは X の問題応答を
domain/x/errors.goのセンチネルエラーに変換します。センチネルエラーを人間が読めるテキストに変換するのは、トランスポート層だけです。そのため、どの 42 個のツールで発生した場合でも、同じエラーは同じ内容で表示されます。
開発
Go のコードはすべて app/ にあります。リポジトリのルートから makefile を使うか、ツールチェーンに -C app を渡してください。
make build # compile the binary -> bin/mcp-x
make test # go test -v ./...
make cover # total coverage percentage
make cover-html # coverage report in the browser
make version # the version that would be stamped into the binary
go -C app build ./...
go -C app test ./...
go -C app vet ./...
モックは、各 usecase インターフェースの隣にある //go:generate ディレクティブを使って mockgen で生成します。
go -C app generate ./...
新しいコードにはテストを付ける必要があります。 プルリクエストのガイドライン全体については、CONTRIBUTING.md を参照してください。
ライセンス
MIT License のもとで公開されています。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。