Skip to main content
Glama
armatrix

twitter-mcp

by armatrix

twitter-mcp + xdata

X (Twitter) data access for Claude Code, split across two front ends over one set of adapters:

  • xdata CLI — all content reads. This is the entry point you want.

  • MCP server — writes, post-volume counts, and usage only.

Zero compilation — edit and run instantly with Bun.

Why reads live in the CLI, not in MCP

Both data providers bill per returned record, and an MCP tool result lands in the model's context in full. One 20-post search is 20–40k tokens of JSON. From a shell the same call can be trimmed, piped through jq, or written straight to disk with only a summary coming back.

Measured, not estimated:

tools

schema in context

a 20-post search in context

before (reads in MCP)

21

~1,898 tok

20,000–40,000 tok

now (reads in CLI)

9

~986 tok

~600 tok (--out: ~30 tok)

The 900-token schema saving is the small half. The point is that large payloads no longer have a path into the conversation at all.

Related MCP server: X (Twitter) MCP Server - Enhanced Edition

Architecture

┌───────────────────────────┐   ┌──────────────────────────────────────┐
│  xdata CLI                │   │  MCP server (twitter-mcp v2.0)       │
│  all content reads        │   │  writes · counts · usage · feeds     │
└─────────────┬─────────────┘   └──────────────┬───────────────────────┘
              │                                │
              ▼                                ▼
   ┌──────────────────────┐         ┌────────────────────┐
   │ ReaderClient  (port) │         │ WriterClient       │  OAuth 1.0a
   ├──────────────────────┤         │ CookieClient       │  ct0 + auth_token
   │ primary              │         │ CountsClient       │  OAuth2 app-only
   │  twitterapi.io       │         └────────────────────┘
   │  $0.00015/post       │
   │       │ on 401/402/429/5xx or an HTTP-200 `status:error`
   │       ▼              │
   │ fallback             │   every fallback is tagged in the response —
   │  official X API v2   │   a silent switch would hide a 33x price jump
   │  $0.005/post         │
   └──────────────────────┘

Which channel for what

Need

Channel

Cost shape

Content (search, timelines, replies, profiles, graph)

twitterapi.io

$0.00015/post, $0.00018/profile

Same, when the primary is out of credits or down

official v2 (auto, tagged)

$0.005/post, $0.010/user — 33x

Volume over time (trends, ranking, spotting peaks)

official counts

$0.005 per request — any match volume, and it does not consume the 3M post-read cap

Writes (post/like/retweet/delete)

official OAuth 1.0a

$0.015/post ($0.20 with a link)

Replies the Free tier blocks (403)

cookie GraphQL

free

The cheap pattern is two-stage: counts first to find which query and which window matter (effectively free), then pull posts for only that window. Large blind searches are the expensive mistake.

Setup

git clone https://github.com/armatrix/twitter-mcp.git && cd twitter-mcp && bun install
mkdir -p ~/.twitter-mcp && cp config.example.json ~/.twitter-mcp/config.json && chmod 600 ~/.twitter-mcp/config.json

~/.twitter-mcp/config.json is the single source of truth for every credential:

{
  "reader":   { "provider": "twitterapi.io", "api_key": "new1_..." },
  "writer":   { "provider": "twitter-official", "api_key": "...", "api_secret_key": "...",
                "access_token": "...", "access_token_secret": "..." },
  "official": { "bearer": "AAAA..." },
  "cookie":   { "ct0": "...", "auth_token": "..." },
  "defaults": { "timeline_count": 20, "search_count": 20 }
}
  • reader.api_key — twitterapi.io. Optional: without it every read falls back to the official API and is tagged as such (33x the price, same capability).

  • writer.* — X Developer Portal → your App → Keys and Tokens.

  • official.bearer — derive it, don't go hunting for it. OAuth 1.0a is rejected by counts, location trends, usage and filtered stream; an app-only bearer is one call away from the consumer key/secret you already have:

    curl -s -u "<consumer_key>:<consumer_secret>" \
         -d 'grant_type=client_credentials' https://api.x.com/oauth2/token
  • cookie.* — DevTools → Application → Cookies → x.com → copy ct0 and auth_token. Optional; only powers the reply fallback. ct0 rotates every few hours.

Install the CLI and register the MCP server:

ln -sf "$PWD/bin/xdata" ~/.local/bin/xdata     # or point a wrapper at src/cli.ts
claude mcp add twitter -- bun run "$PWD/src/index.ts" -config ~/.twitter-mcp/config.json

CLI

xdata usage                                    # both providers: balance, spend, cap
xdata counts '<query>' --day|--hour [--all]    # per-request billing → trends & ranking
xdata search '<q> min_faves:30' --top -n 20    # min_faves is server-side (official v2 lacks it)
xdata user|about|timeline|mentions <handle>
xdata replies|quotes|thread|retweeters <tweetId>
xdata tweets <id,id,...>                       # batch by id
xdata batch-users <id,id,...>                  # bulk profiles, cheaper per user
xdata followers|followings <handle>
xdata follower-ids <handle>                    # IDs only: 0.45cr vs 18cr per profile — 40x cheaper
xdata verified-followers <handle>              # $0.3/1000
xdata usersearch <query>                       # no official equivalent exists
xdata follows <a> <b>                          # mutual-follow check (100cr)
xdata article <tweetId>                        # long-form body (no official equivalent)
xdata trends [woeid]

Output control — this is where the token savings are:

--out FILE   full JSON to disk, one summary line to stdout
--json       raw          --jsonl   one record per line (pipe to jq)
-n N         max records  -w N      text column width      -q  no summary line

Every command prints cost≈, because both providers bill per record and it is otherwise invisible until the dashboard catches up.

MCP tools (9)

Tool

Channel

Notes

post_tweet

OAuth 1.0a → cookie

Up to 4 images; auto-falls back to cookie auth on a reply 403

like_tweet unlike_tweet retweet delete_tweet

OAuth 1.0a

get_tweet_counts

official app-only

Per-request billing; counts only (no text/authors)

get_api_usage

official app-only

Post reads against the monthly cap + estimated spend

get_for_you_feed get_following_feed

cookie

The authenticated account's own timelines

There are deliberately no content-read tools here. The server says so on startup.

Reply fallback

post_tweet(text, reply_to_tweet_id) → OAuth 1.0a POST /2/tweets
  ├─ 200 → done (method: "oauth")
  └─ 403 (Free tier reply restriction) → cookie GraphQL CreateTweet (method: "cookie")
                                       → or an error if no cookie is configured

Endpoint index

docs/endpoint-index.md — 264 endpoints across both providers, generated from their machine-readable specs (api.x.com/2/openapi.json v2.168 / 157 paths + twitterapi.io / 76 paths), grouped by function with auth requirements and billing per row. Consult it before assuming a capability is missing.

⚠️ A spec is a lead, not a fact. /twitter/user/tweet_timeline is documented with a top-level tweets array but actually answers data.tweets; the adapter accepts both, because reading only one shape yields an empty array indistinguishable from "no results".

Known limitations

Issue

Reality

/twitter/user/following looks broken

It isn't a route — the path is followings (plural). Wrong URLs answer HTTP 200 status:error msg:"user not found"

last_tweets ignores count

No such parameter; a page is always ~20 and you are billed per returned tweet. Narrow with cursor, and prefer the stream API for monitoring — the endpoint docs say polling it frequently "will cost you a lot"

Official counts/trends/usage/stream return 403

They reject OAuth 1.0a. Use official.bearer

Official v2 has no user search, and no long-form article body

Only twitterapi.io has these

firehose / sample streams

403 — Enterprise tier

Filtered stream billing

Not in the pricing page; rule slots are visible (cap_per_client_app: 5, cap_per_project: 15) but per-delivery cost is unverified

Free-tier OAuth blocks replies to non-interacted posts

Cookie fallback handles it

ct0 rotates every few hours

Re-copy from the browser when cookie auth starts failing

Project structure

src/
├── cli.ts                      # xdata — all content reads
├── index.ts                    # MCP server — writes, counts, usage, feeds
├── config.ts
├── clients/
│   ├── reader.ts               # port + router (primary → tagged fallback)
│   ├── reader-twitterapi.ts    # primary adapter
│   ├── reader-official.ts      # fallback adapter (X API v2, OAuth 1.0a)
│   ├── counts.ts               # app-only bearer: counts / trends / usage
│   ├── writer.ts               # OAuth 1.0a writes + media upload
│   └── cookie.ts               # GraphQL via browser session
├── lib/
│   ├── normalize-tweet.ts      # GraphQL → NormalizedTweet
│   └── v2-to-normalized.ts     # X API v2 → NormalizedTweet
└── tools/
    ├── discovery.ts            # get_tweet_counts, get_api_usage, cookie feeds
    └── write.ts                # post/like/unlike/retweet/delete
docs/
├── endpoint-index.md           # both providers, generated from specs
PATCH-reader-dual-channel.md    # why it is built this way + what was learned the hard way

Development

No build step. Edit and restart the server (stdio servers do not hot-reload — /mcp reconnect after changing anything the server loads).

bun run src/index.ts -config ~/.twitter-mcp/config.json
bunx tsc --noEmit

Tech stack

Bun · @modelcontextprotocol/sdk · oauth-1.0a · bun:sqlite · X internal GraphQL (no deps)

License

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    An MCP server that enables Claude to interact with Twitter, allowing for posting tweets and searching Twitter content.
    2
    280 npm
    407
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    An enhanced Model Context Protocol server that enables Claude to interact with Twitter/X, supporting tweet posting, searching, and deletion with both OAuth 1.0a and OAuth 2.0 authentication methods.
    109 npm
    24
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Model Context Protocol server that enables programmatic interaction with Twitter API, allowing users to post tweets, search for content, and retrieve user timelines through standardized MCP tools.
    5 npm
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    An MCP server for interacting with the Twitter/X API v2, enabling AI assistants to retrieve tweets, post content, reply, quote, and more programmatically.
    3,240 npm
    13
    MIT