X平台多账户管理服务

一个基于Rust构建的X平台多账户管理服务,支持通过JSON-RPC 2.0协议进行推文发布、媒体上传、账户管理等操作。

  • by codeChap
  • Rust
  • 本地部署
  • 更新于
在 GitHub 查看 codeChap/mcp-server-post-x

使用说明

mcp-server-x

An MCP (Model Context Protocol) server for X (Twitter). Built in Rust using OAuth 1.0a and the X API v2. Supports multiple accounts.

Communicates via stdio using JSON-RPC 2.0.

Tools

Tool Description
list_accounts List available accounts and which is the default
post_tweet Post a tweet with optional media (up to 4 images, 1 video, or 1 GIF)
post_thread Post a thread of up to 25 tweets, each with optional media
delete_tweet Delete a tweet by ID or URL
upload_media Upload media for later attachment (returns a media_id)
update_profile Update your bio/description, display name, location, and/or website URL (legacy v1.1 endpoint)
update_profile_banner Update profile header/banner image (legacy v1.1 endpoint)
search_tweets Search recent tweets (last 7 days) with Twitter operators
get_timeline Get your home timeline in reverse chronological order
get_bookmarks Get your bookmarked tweets (paginated)
get_me Get the authenticated user's profile
lookup_user Look up any user by @username or numeric ID
get_followers List your followers (paginated)
get_following List who you follow (paginated)
get_all_followers Fetch ALL your followers in a single call (auto-paginates)
get_all_following Fetch ALL accounts you follow in a single call (auto-paginates)
like_tweet Like a tweet by ID or URL
unlike_tweet Unlike a tweet by ID or URL
retweet Retweet a tweet by ID or URL
unretweet Undo a retweet by ID or URL
bookmark_tweet Bookmark a tweet by ID or URL
unbookmark_tweet Remove a bookmark by ID or URL
get_trends Get current trending topics for a WOEID location (default: worldwide)
get_dm_events Get recent direct messages across all conversations
send_dm Send a direct message to a conversation
follow_user Follow a user by username or ID
unfollow_user Unfollow a user by username or ID

All tools accept an optional account parameter to select which X account to use. Omit it to use the default account.

Quick Start

1. Build

cargo build --release

Produces target/release/mcp-server-x (optimized with LTO, stripped).

2. Configure credentials

The server looks for the config at the first existing of:

  • $XDG_CONFIG_HOME/mcp-server-x/config.toml
  • ~/.config/mcp-server-x/config.toml
  • $XDG_CONFIG_HOME/mcp-server-post-x/config.toml (legacy)
  • ~/.config/mcp-server-post-x/config.toml (legacy)

You can also run without any config file by providing credentials via environment variables (great for containers/CI):

export X_API_KEY=...
export X_API_KEY_SECRET=...
export X_ACCESS_TOKEN=...
export X_ACCESS_TOKEN_SECRET=...
# Optional:
# export X_ACCOUNT_NAME=myaccount

POST_X_* / POST_X_ACCOUNT_NAME are still accepted if the X_* vars are unset.

Create the config file (classic approach):

mkdir -p ~/.config/mcp-server-x

Create ~/.config/mcp-server-x/config.toml:

Single account (no default_account needed):

[accounts.myaccount]
api_key = "your-api-key"
api_key_secret = "your-api-key-secret"
access_token = "your-access-token"
access_token_secret = "your-access-token-secret"

Multiple accounts:

default_account = "myaccount"

[accounts.myaccount]
api_key = "your-api-key"
api_key_secret = "your-api-key-secret"
access_token = "your-access-token"
access_token_secret = "your-access-token-secret"

[accounts.otheraccount]
api_key = "your-api-key"
api_key_secret = "your-api-key-secret"
access_token = "other-access-token"
access_token_secret = "other-access-token-secret"

Notes:

  • Account keys are X usernames (e.g. [accounts.codechap])
  • If you have multiple accounts, default_account is required
  • If you have one account, default_account is optional (auto-detected)
  • Multiple accounts can share the same api_key/api_key_secret (same X app). Only the access_token/access_token_secret differ per account.
  • bookmark_tweet / unbookmark_tweet require OAuth 2.0 User Context (bookmark.write). Add optional oauth2_client_id, oauth2_client_secret, oauth2_access_token, and oauth2_refresh_token on the account that needs bookmarks. OAuth 1.0a stays in use for every other tool. Generate the user token in the X Developer Console (App → Keys & Tokens → OAuth 2.0 Access Token) with tweet.read, users.read, bookmark.read, bookmark.write, and offline.access. Access tokens last ~2 hours; the server refreshes them with oauth2_refresh_token (and writes the rotated tokens back to config.toml).

Secure it:

chmod 700 ~/.config/mcp-server-x
chmod 600 ~/.config/mcp-server-x/config.toml

See Getting credentials below for how to obtain these.

3. Add to your MCP client

Claude Code (~/.claude.json):

{
  "mcpServers": {
    "x": {
      "command": "/path/to/mcp-server-x"
    }
  }
}

Then ask Claude things like:

  • "Post a tweet saying hello world"
  • "Post a tweet as securechap saying hello world"
  • "Search for tweets about Rust"
  • "Show me my timeline"
  • "Like this tweet: https://x.com/someone/status/123456"
  • "Who are my followers?"
  • "Look up @elonmusk"
  • "List my accounts"

Tool Reference

list_accounts

No required parameters. Returns available account names, which is the default, and cached usernames.

post_tweet

Param Type Required Description
account string no Account to use (omit for default)
text string yes Tweet text (max 280 characters)
media array no Media to upload and attach. Each item: { path, alt_text? }. Max 4 images, or 1 video, or 1 GIF.
media_ids array no Pre-uploaded media IDs to attach (max 4). Mutually exclusive with media.
reply_to string no Tweet ID to reply to

post_thread

Param Type Required Description
account string no Account to use (omit for default)
tweets array yes Array of tweets (max 25). Each: { text, media? }

delete_tweet / like_tweet / unlike_tweet / retweet / unretweet / bookmark_tweet / unbookmark_tweet

Param Type Required Description
account string no Account to use (omit for default)
tweet_id string yes Tweet ID or full tweet URL

All accept URLs like https://x.com/user/status/123456 — the ID is extracted automatically.

upload_media

Param Type Required Description
account string no Account to use (omit for default)
path string yes Local file path. Supported: jpeg/png/webp (max 5MB), gif (max 15MB), mp4 (max 512MB)
alt_text string no Alt text (images and GIFs only, not video)

Returns a media_id to use with post_tweet's media_ids param.

update_profile

Update the authenticated user's profile text fields. At least one field must be provided; only the fields you pass are changed, and passing an empty string clears that field.

Param Type Required Description
account string no Account to use (omit for default)
description string no* New bio/description (max 160 chars; empty string clears it)
name string no* New display name (1-50 chars)
location string no* New location (max 30 chars; empty string clears it)
url string no* New website URL shown on the profile (max 100 chars; empty string clears it)

* At least one of description, name, location, or url is required.

Uses the legacy POST /1.1/account/update_profile.json endpoint (no v2 equivalent). Requires the app to have Read and Write permission; without it the endpoint returns 403.

update_profile_banner

Param Type Required Description
account string no Account to use (omit for default)
path string yes Local file path to banner image (JPEG/PNG/WebP only, max 5MB). X recommends 1500x500 pixels.
width integer no Width of the image (for cropping)
height integer no Height of the image (for cropping)
offset_left integer no Left offset (pixels) for crop start
offset_top integer no Top offset (pixels) for crop start

Uses the legacy POST /1.1/account/update_profile_banner.json endpoint (base64 banner param; no v2 equivalent). Success returns HTTP 200 with no body.

search_tweets

Param Type Required Description
account string no Account to use (omit for default)
query string yes Search query. Supports: from:user, #hashtag, @mention, "exact phrase", -exclude, lang:en
max_results integer no 10-100 (default 10)
sort_order string no recency or relevancy
pagination_token string no Next page token from previous response

get_trends

Param Type Required Description
account string no Account to use (omit for default; determines which app's rate limit is used)
woeid integer no WOEID for location (default: 1 = Worldwide). See common values in tool description.

Returns trend names and approximate post volumes.

get_timeline

Param Type Required Description
account string no Account to use (omit for default)
max_results integer no 1-100 (default 20)
exclude string no replies, retweets, or both comma-separated
pagination_token string no Next page token

get_bookmarks

Param Type Required Description
account string no Account to use (omit for default)
max_results integer no 1-100 (default 20)
pagination_token string no Next page token

lookup_user / follow_user / unfollow_user

Param Type Required Description
account string no Account to use (omit for default)
user string yes Username (with or without @) or numeric user ID

get_followers / get_following

Param Type Required Description
account string no Account to use (omit for default)
max_results integer no 1-100 (default 20)
pagination_token string no Next page token

get_all_followers / get_all_following

Param Type Required Description
account string no Account to use (omit for default)
max_users integer no Safety cap (default 5000, max 10000). Prevents huge responses for high-follower accounts.

Auto-paginates through results (100 per page) with a 200ms delay between pages. For accounts with tens of thousands of followers, prefer the paginated get_followers / get_following tools instead.

get_dm_events

Param Type Required Description
account string no Account to use (omit for default)
max_results integer no 1-100 (default 20)
pagination_token string no Next page token

send_dm

Param Type Required Description
account string no Account to use (omit for default)
conversation_id string yes DM conversation ID (get from get_dm_events)
text string yes Message text

get_me

Param Type Required Description
account string no Account to use (omit for default)

Returns your user ID, display name, and @username.

Adding Additional Accounts

To add another X account to an existing app (without a separate developer account), use the included OAuth authorization script:

export X_API_KEY="your-app-api-key"
export X_API_KEY_SECRET="your-app-api-key-secret"
./oauth-authorize.sh

Important: The script no longer contains any hardcoded credentials. You must provide your own app's Consumer Keys via the two environment variables shown above.

This runs the 3-legged OAuth 1.0a PIN-based flow:

  1. Opens a URL where the new account authorizes your app
  2. You paste the PIN back into the terminal
  3. It outputs the [accounts.username] config block to add to your config.toml

All accounts you authorize share the same X App (and its rate limits + billing). This is the normal pattern for multi-account usage.

Getting Credentials

  1. Go to developer.x.com and sign up for a developer account
  2. Create a Project and an App in the Developer Console
  3. In your App settings, set up User authentication:
    • App permissions: Read and write (and Direct Messages if you want DM support)
    • Type: Web App, Automated App or Bot
    • Callback URL: https://example.com (not used, but required)
    • Website URL: any valid URL
  4. Go to Keys and tokens and generate:
    • API Key and API Key Secret (under Consumer Keys)
    • Access Token and Access Token Secret (under Authentication Tokens)
  5. Copy all four values into your config.toml under [accounts.yourusername]

The server validates credentials at startup. If you get persistent 401 errors, regenerate your tokens at developer.x.com.

Development

cargo build              # debug build
cargo run                # run in dev mode
RUST_LOG=debug cargo run # debug logging (credentials are redacted)

cargo test               # run unit tests
cargo clippy -- -D warnings   # strict lint check (must pass)
cargo build --release    # optimized binary

Technical Details

  • Auth: OAuth 1.0a with HMAC-SHA1 signatures (RFC 5849, RFC 3986 percent-encoding)
  • Multi-account: Multiple X accounts per server instance, selectable per tool call
  • Tweet API: X API v2 (api.x.com/2/)
  • Media upload: v1.1 chunked upload (upload.twitter.com/1.1/media/upload.json) — INIT/APPEND/FINALIZE/STATUS flow for video/GIF, simple multipart for images
  • Media limits: JPEG/PNG/WebP up to 5MB, GIF up to 15MB, MP4 up to 512MB
  • Media validation: Max 4 images OR 1 video OR 1 GIF per tweet (no mixing)
  • Thread posting: 500ms delay between tweets, chained via in_reply_to_tweet_id
  • Retry logic: Automatic retry with exponential backoff on 503 errors
  • Rate limits: 429 responses include reset timestamp in error message (no auto-retry — the caller decides)
  • Safety: get_all_followers / get_all_following are capped at 10k users by default to avoid destroying LLM context windows
  • Rust edition: 2021 (broad compatibility)

Project Structure

src/
  main.rs    — entry point, config loading, tracing, stdio transport
  server.rs  — MCP tool handlers, response formatting, multi-account routing
  api.rs     — X API client: OAuth signing, tweet/media/user/DM endpoints
  params.rs  — tool parameter types (serde + JSON Schema)