x-wing-mcp
A stdio MCP server for X (Twitter) that combines x-wing write tools with x_data read tools.All tools share one process, one .env, and one official xdk OAuth 2.0 app.
Tools
Write tools
| Tool | Description | Required scope |
|---|---|---|
post |
Create a single post | tweet.write |
create_thread |
Create a multi-post thread | tweet.write |
like |
Like a post | like.write |
repost |
Repost a post | tweet.write |
follow |
Follow a user by ID | follows.write |
unfollow |
Unfollow a user by source/target ID | follows.write |
dm_send |
Send a direct message | dm.write |
Read tools
| Tool | Description | Required scope |
|---|---|---|
x_fetch_urls |
Fetch exact public posts by URL/ID | tweet.read |
x_read_user_posts |
Recent posts for one user | tweet.read + users.read |
x_search_posts |
Search public posts | tweet.read |
x_read_owned_timeline |
Authenticated account timeline | tweet.read |
x_read_mentions |
Mentions for the authenticated account | tweet.read |
x_read_thread |
Thread/conversation from an anchor post | tweet.read |
x_read_replies |
Replies to one post | tweet.read |
x_read_quotes |
Quote posts of one post | tweet.read |
x_read_follow_graph |
Followers/following for one user | follows.read |
x_read_article |
Published X Article via wrapper tweet | tweet.read |
x_collect_posts |
One-shot bulk collection query | tweet.read |
x_data_status |
Server/provider status | none |
x_data_healthcheck |
Provider diagnostics | none |
x_usage_stats |
Local usage/cost ledger summary | none |
x_read_own_analytics |
Owned-account analytics from the local x-analytics service (read-only, never fetches) | none (local HTTP) |
Read tools use an internal provider router (official_x, syndication, socialdata, getxapi).max_cost_usd is required on every read tool except status/healthcheck.
Provisioning
- Ensure this repo's
.envexists and is readable only by the owner:chmod 600 .env - Populate
.envwith OAuth 2.0 credentials from the X developer portal:
Legacy aliases (X_OAUTH2_CLIENT_ID=... X_OAUTH2_CLIENT_SECRET=... X_OAUTH2_ACCESS_TOKEN=... X_OAUTH2_REFRESH_TOKEN=... X_OAUTH2_SCOPES="offline.access dm.read tweet.write like.write like.read users.read dm.write tweet.read bookmark.write follows.write follows.read"X_CLIENT_ID,X_CLIENT_SECRET,X_ACCESS_TOKEN,X_REFRESH_TOKEN,X_SCOPES) are also accepted. - Optional paid/backup providers:
Leave blank to rely onSOCIALDATA_API_KEY=... GETXAPI_API_KEY=...official_x+syndicationonly. - If the access token is expired, run the included OAuth setup script or use the CLI refresh path to obtain a fresh token.
Running
./x-wing-mcp-hermes.sh
The wrapper uses the repo-local uv environment and launches the server overstdio. stdout is the MCP protocol stream - no other process should write to it.
Analytics integration
x_read_own_analytics is a read-only client of the separate localx-analytics service. It reads the service's stored observations overloopback HTTP and never opens an analytics database or calls X directly.
Collection, OAuth credentials, spend limits, and freshness policy belong tothe x-analytics deployment. Keep this MCP tool read-only: agents must notbe able to trigger paid analytics collection.
Configure the local endpoint in config/analytics.yaml. x-wing accepts onlyan http loopback origin, uses a bounded timeout, rejects redirects andoversized/non-JSON responses, and reports a distinct ANALYTICS_SERVICE errorwhen the service is missing or unreachable.
The MCP tool defaults to view="overview". It also supports posts,post_history (requires post_id), followers, and status, with awindow_days of 1–30. Responses use x-analytics' versioned envelope with anas_of timestamp and freshness state. Post metrics are cumulative at as_of;reported change always names the two observation timestamps rather thanpretending to be a calendar-period total.
Testing
python -m pytest tests/ -q
Project layout
.
├── .env # real tokens, gitignored, chmod 600
├── .env.example # committed template
├── .gitignore # ignores .env and auth-state files
├── pyproject.toml # x-wing-mcp package metadata
├── README.md # this file
├── x_client.py # vendored + patched x-wing client
├── oauth_setup.py # vendored + patched OAuth setup
├── server.py # FastMCP stdio server (read + write tools)
├── xdata/ # vendored x_data read providers/router/server
├── config/ # provider routing configuration
└── tests/ # vendored + new MCP tests
Verification
uv run python -m pytest tests/ -qpasses.- An MCP handshake via the wrapper script (
initialize→tools/list) returns the22 tools documented above. x_data_statusreports the configured providers' health without exposing credentials.- A token check against
users/mesucceeds, and.envplus auth-state files remainowner-readable only.
Deployment notes
- This repository is relocatable: configure the MCP host with the absolute path to
x-wing-mcp-hermes.shin its checked-out repository. - Store X credentials only in
<repo_root>/.env(mode0600). Do not duplicate orsource them from shared host, agent-profile, or global environment files. - Register one x-wing MCP server per intended host/profile and apply that host'stool-access policy—for example, exclude write tools from read-only profiles.
- The wrapper reads only the repository-local
.envand keeps stdout reserved forthe stdio MCP protocol.
Roadmap
See AGENTS.md. Repo reconciliation isalready complete: this repo (bob0x-ai/x-wing-mcp) is the canonical source of truth.