X (Twitter) API client library with tweepy and pydantic
Project description
X (Twitter) API クライアント リデザイン
X (Twitter) API と連携するための Python クライアントです。tweepy をベースに v2 API (投稿) と v1.1 API (メディアアップロード) を統合し、シンプルに運用できるよう再設計しました。
主な機能
- デュアルクライアント構成:投稿は tweepy.Client (v2)、メディアは tweepy.API (v1.1)
.envを用いた安全な認証情報管理と OAuth フロー統合PostService/MediaServiceによる高レベル APIexamples/create_post.pyによる CLI からの投稿デモ- 長文スレッド投稿ユーティリティと自動リプライチェーン構築
- リポスト/取り消し API と MCP ツール
- 検索 API の expansions/fields 指定対応と著者情報解決
- サービス層に組み込まれた構造化ログとイベントフック
- MCP (Model Context Protocol) 統合: AI アシスタントから X API を操作可能
必要条件
- Python 3.13 以上
- X (Twitter) 開発者アカウントと API キー一式
- パッケージ管理ツール uv(推奨)
インストール
uv sync
認証情報の設定
.env または環境変数で認証情報を設定します。.env は初回保存時に自動的に 0o600(所有者のみ読み書き可)になります。
- Python 3.13+ を想定。パッケージ管理には
uvを利用。 - 依存関係インストール:
uv sync環境変数で設定する場合(推奨):
export X_API_KEY="your_api_key"
export X_API_SECRET="your_api_secret"
export X_ACCESS_TOKEN="your_access_token"
export X_ACCESS_TOKEN_SECRET="your_access_token_secret"
export X_BEARER_TOKEN="your_bearer_token" # v2 API用(オプション)
.env ファイルを利用する場合(プロジェクト直下に配置):
# .env
X_API_KEY=your_api_key
X_API_SECRET=your_api_secret
X_ACCESS_TOKEN=your_access_token
X_ACCESS_TOKEN_SECRET=your_access_token_secret
X_BEARER_TOKEN=your_bearer_token
.env はリポジトリ直下に置くと ConfigManager が自動的に読み込みます。別パスを使う場合は ConfigManager(dotenv_path=Path("/path/to/.env")) のように明示してください。 .env* は .gitignore 済みのため、バージョン管理に含めないでください。OAuth フロー経由で取得したトークンは ConfigManager.save_credentials() により .env に追記されます。
ライブラリとして利用する
クライアントをコードから直接呼び出すには、以下のようにインポートしてください。
from x_client.config import ConfigManager
from x_client.factory import XClientFactory
from x_client.services.post_service import PostService
from x_client.services.media_service import MediaService
# 1. 認証情報を読み込み
config = ConfigManager()
client = XClientFactory.create_from_config(config)
# 2. サービス層を初期化
post_service = PostService(client)
media_service = MediaService(client)
# 3. 投稿を作成
post = post_service.create_post(text="Hello from x_client!")
print(f"Post created: {post.id}")
# 4. 画像付き投稿
from pathlib import Path
media_result = media_service.upload_image(Path("image.png"))
post = post_service.create_post(
text="Check out this image!",
media_ids=[media_result.media_id]
)
# 5. 長文スレッド投稿
thread = post_service.create_thread(
"""Python 3.13 highlights... (long text)""",
chunk_limit=200,
)
for idx, segment_post in enumerate(thread.posts, start=1):
print(f"Segment {idx}: {segment_post.id}")
if not thread.succeeded:
print("Thread failed", thread.error)
# 6. リポスト操作
repost_state = post_service.repost_post(post.id)
print("Reposted:", repost_state.reposted)
undo_state = post_service.undo_repost(post.id)
print("Repost removed:", not undo_state.reposted)
# 7. 著者情報付き検索
search_results = post_service.search_recent(
"from:twitterdev",
expansions=["author_id"],
user_fields=["username", "verified"],
post_fields=["created_at"],
)
for item in search_results:
author = item.author.username if item.author else "unknown"
print(author, item.text)
CLI で試す
examples/create_post.py を使うと、簡単に投稿を試せます。
# テキストのみ
python examples/create_post.py "Hello from x_client!"
# 画像付き
python examples/create_post.py "Check out this image!" --image path/to/image.png
# 動画付き(最大512MB、チャンクアップロード対応)
python examples/create_post.py "Check out this video!" --video path/to/video.mp4
# 別パスの .env を利用
python examples/create_post.py "Hello with custom env" --dotenv /secure/path/.env
# 長文スレッド投稿(chunk_limit=180 で自動分割)
python examples/create_post.py "Long form update..." --thread --chunk-limit 180
# ファイルからスレッドを投稿(UTF-8 テキストを想定)
python examples/create_post.py --thread-file docs/thread_draft.txt
# 日本語の長文スレッド例(280文字未満で適度に改行)
python examples/create_post.py --thread-file examples/long_thread_ja.txt --chunk-limit 180
# 英語の長文スレッド例(センテンス区切りを維持)
python examples/create_post.py --thread-file examples/long_thread_en.txt --chunk-limit 240
# レートリミット回避のため各投稿間で 8 秒待つ
python examples/create_post.py --thread-file examples/long_thread_en.txt --segment-pause 8
# 失敗したスレッドの先頭ツイートを削除(重複エラーの解消に利用)
python examples/create_post.py --delete 1234567890123456789
# リポスト / リポストの取り消し
python examples/create_post.py --repost 1234567890
python examples/create_post.py --undo-repost 1234567890
examples/sample_image.png をサンプル画像として同梱しているため、動作確認時には --image examples/sample_image.png を指定できます。
スレッド投稿はテキストのみサポートしています(API 制約上メディア添付は不可)。--chunk-limit で 1 セグメントあたりの文字数上限を調整できます。--thread-file を指定すると Markdown/テキストファイルをそのままスレッドとして分割投稿します。
ロングスレッド投稿における言語別の考慮事項
- 日本語: 全角文字が多い場合は 280 文字ギリギリまで詰めると読みづらくなるため、
--chunk-limitを 150-200 文字程度に抑えて文節ごとのまとまりを維持してください。また、句読点直後で分割されると文脈が途切れやすいので、テキストファイル側で段落ごとに空行を入れておくと安全です。UTF-8 のまま保存すれば X API で正しく扱われます。 - 英語: URL や絵文字を含むときは Twitter 側で 23 文字換算されるため、余裕を持って
--chunk-limitを設定します。センテンス単位で改行しておくと、分割後も読みやすさが保たれます。また、引用符や Markdown 記法を使う場合は、変換後に 280 文字を超えていないか冒頭のドラフト投稿で必ず確認してください。
スレッドを再投稿する場合、X 側の仕様で 24 時間以内に全く同じ本文を投稿すると Duplicate content エラーになります。前回投稿したスレッドを削除するか、テキストにタイムスタンプなどの一意な語句を追加してから再実行してください。--delete オプションで先頭ツイートを素早く削除できます。
また、X API は短時間に連続で投稿すると HTTP 429 (Too Many Requests) を返すことがあります。本ライブラリでは RateLimitExceeded を検知するとレスポンスヘッダーの x-rate-limit-reset に従って待機してから再試行しますが、手動投稿でも同じ制限があるため、429 が発生した場合は 2~3 分ほど待ってからコマンドを再実行してください。
--segment-pause を 5–10 秒程度に設定するとセグメントごとの投稿間隔に余裕を持たせられ、429 を事前に回避しやすくなります。
リポスト操作は本文/メディア不要で、--repost で指定 ID をリポスト、--undo-repost で取り消します。
ロギングと可観測性
PostService には構造化された INFO/DEBUG ログとイベントフックが標準で組み込まれています。logging.basicConfig(level=logging.INFO) を呼び出すだけで、スレッド投稿やリポストの進行状況が post.thread.* / post.repost.* といったイベント名で確認できます。
import logging
from x_client.config import ConfigManager
from x_client.factory import XClientFactory
from x_client.services.post_service import PostService
logging.basicConfig(level=logging.INFO)
client = XClientFactory.create_from_config(ConfigManager())
def metrics_hook(event: str, payload: dict[str, object]) -> None:
# Prometheus / OpenTelemetry などへの連携ポイント
print("metrics", event, payload)
post_service = PostService(client, event_hook=metrics_hook)
post_service.create_post("observability ready!")
イベントフックは成功・失敗双方のイベントを単一コールバックへ集約するため、メトリクス送出や分散トレーシングとの連携が容易です。失敗時には post.create.error や post.thread.error が呼び出されるため、再試行戦略やアラート通知と組み合わせられます。
MCP (Model Context Protocol) で利用する
このライブラリ(GitHub: pyX-MCP)は標準的な MCP サーバーとして AI アシスタント(Claude Desktop など)から利用できます。
🚀 最も簡単な方法:uvx で実行(PyPI 公開後)
PyPI に公開済みであれば、以下のように使用できます:
uvx --from pyx-mcp x-mcp-server
Claude Desktop 設定例:
{
"mcpServers": {
"x-client": {
"command": "uvx",
"args": ["--from", "pyx-mcp", "x-mcp-server", "--stdio"],
"env": {
"X_API_KEY": "your-api-key",
"X_API_SECRET": "your-api-secret",
"X_ACCESS_TOKEN": "your-access-token",
"X_ACCESS_TOKEN_SECRET": "your-access-token-secret"
}
}
}
}
メリット:
- ✅ Node.js なしで利用可能(uv が自動で仮想環境を構築)
- ✅ 依存関係は
uvのキャッシュを利用して高速化 - ✅
--fromにより常に最新リリースへ簡単に更新
開発環境での利用
1. セットアップ (初回のみ):
cd /path/to/twitter
uv pip install -e .
これにより x-mcp-server コマンドが .venv/bin/ に作成されます。
2. Claude Desktop の設定ファイルを編集:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
推奨: uvx エントリーポイント使用
{
"mcpServers": {
"x-client": {
"command": "/absolute/path/to/twitter/.venv/bin/x-mcp-server",
"env": {
"X_API_KEY": "your-api-key",
"X_API_SECRET": "your-api-secret",
"X_ACCESS_TOKEN": "your-access-token",
"X_ACCESS_TOKEN_SECRET": "your-access-token-secret"
}
}
}
}
代替方法 (クリックして展開)
方法2: uv 直接使用
{
"mcpServers": {
"x-client": {
"command": "uv",
"args": ["run", "--directory", "/absolute/path/to/twitter", "python", "-m", "x_client.integrations.mcp_server"],
"env": {
"X_API_KEY": "your-api-key",
"X_API_SECRET": "your-api-secret",
"X_ACCESS_TOKEN": "your-access-token",
"X_ACCESS_TOKEN_SECRET": "your-access-token-secret"
}
}
}
}
方法3: ランチャースクリプト
{
"mcpServers": {
"x-client": {
"command": "/absolute/path/to/twitter/scripts/run_mcp_server.sh",
"env": { "X_API_KEY": "...", "X_API_SECRET": "...", "X_ACCESS_TOKEN": "...", "X_ACCESS_TOKEN_SECRET": "..." }
}
}
}
重要:
/absolute/path/to/twitterを実際のプロジェクトパスに置き換え- 認証情報を実際の X API 資格情報に置き換え
2. Claude Desktop を再起動
3. 動作確認:
Claude に「利用可能な X API ツールを一覧表示して」と依頼すると、10個のツールが表示されます。
使用例
あなた: 「Hello from Claude via MCP!」と投稿して
Claude: create_post ツールを使用します...
投稿が完了しました!投稿ID: 1234567890
あなた: 「MCP プロトコル」について最近の投稿を検索して
Claude: search_recent_posts ツールを使用します...
3件の投稿が見つかりました:
1. @user1: MCP を使ってみた...
2. @user2: Model Context Protocol は...
Python API としても利用可能
MCP クライアント以外からも直接呼び出せます:
from x_client.integrations.mcp_adapter import XMCPAdapter
adapter = XMCPAdapter() # 認証情報は ConfigManager が自動読み込み
post = adapter.create_post({"text": "Hello from MCP!"})
print(post)
media = adapter.upload_image({"path": "/path/to/image.png"})
adapter.create_post({"text": "Image post", "media_ids": [media["media_id"]]})
アーキテクチャ
Claude Desktop ↔ MCP Server (stdio) ↔ XMCPAdapter ↔ Service Layer ↔ X API
提供ツール
create_post,delete_post,get_post,search_recent_postscreate_thread,repost_post,undo_repostupload_image(画像: JPEG/PNG/WebP/GIF, 最大 5MB)upload_video(動画: MP4, 最大 512MB, チャンクアップロード対応)get_auth_status(OAuth1 アクセストークンからuser_idを抽出し、利用可能であればレート制限情報{limit, remaining, reset_at}を返却)
エラーハンドリング
ConfigurationError: 認証情報不足。.envと環境変数を確認。AuthenticationError: トークン失効。OAuth フローを再実行。RateLimitExceeded: レート制限到達。reset_atを参照し、バックオフを実施。MediaProcessingTimeout/MediaProcessingFailed: 動画処理が完了しない場合。timeoutや動画品質を調整。
トラブルシューティング
- Missing credentials:
echo $X_API_KEYなどで環境変数を確認し、.envが 0o600 で保存されているか確認する。 - Invalid token:
python examples/create_post.py "test"を実行して OAuth フローを復旧。 - Video timeout:
upload_videoのtimeoutを延長するか、ffmpegで再エンコードする。
詳細ドキュメント
MCP サーバーの詳細な設定とトラブルシューティングは docs/mcp_setup.md を参照してください。
テスト
# MCP サーバーの動作テスト
uv run python scripts/test_mcp_server.py
# ユニットテスト
uv run pytest tests/unit/test_mcp_adapter.py -v
ドキュメント
詳細な設計・計画や既知の懸念点は docs/x_api_design.md を参照してください(プロジェクト内ドキュメントはこの1ファイルに統合されています)。
テスト実行
# 全テスト実行
uv run pytest
# カバレッジ付き実行
uv run pytest --cov=x_client --cov-report=html
# 詳細モード
uv run pytest -v
# 特定のテストファイル
uv run pytest tests/unit/test_tweepy_client.py
サポート
バグ報告や改善提案は issue もしくは pull request でお知らせください。プロジェクト方針や設計に関する詳細は docs/ を参照のうえ、必要に応じてコメントを追加してください。
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyx_mcp-0.1.1.tar.gz.
File metadata
- Download URL: pyx_mcp-0.1.1.tar.gz
- Upload date:
- Size: 31.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
87f725a6495f4dee40d3d5d3d7e23759581bb35422d8355949e119225c897347
|
|
| MD5 |
876c3676b70bff212ce797ac2ec7526a
|
|
| BLAKE2b-256 |
533913b92d570796373f77656e4095c9d36e3ccccfda661344bb40b69e4f5886
|
File details
Details for the file pyx_mcp-0.1.1-py3-none-any.whl.
File metadata
- Download URL: pyx_mcp-0.1.1-py3-none-any.whl
- Upload date:
- Size: 38.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8d15026def34e67c02b29374e6aed4fecc52c5afea55c3f0e85fc74fe72da7e
|
|
| MD5 |
84a9d654806b41aba8823b69846b8fae
|
|
| BLAKE2b-256 |
d40b839b96711d11f5cc07b51d3af2bd54e55ef31f3e41a45ef1ab227f3c1cb6
|