@twitterapis/mcp 0.11.1 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.12.0 (2026-09-13)
4
+
5
+ - **Two new tools, 107 -> 109 (65 reads, 44 writes): `twitter_update_avatar` and
6
+ `twitter_update_banner`.** Both endpoints had been serving behind a feature flag
7
+ on the API and documented on no surface, because their upstream host was an
8
+ INFERENCE from the sibling profile write rather than an observation. Both have
9
+ now been called end to end against a live account, both success envelopes were
10
+ captured, and each write was confirmed applied by reading the profile back
11
+ through the GraphQL user lookup. The flag is deleted from the API entirely.
12
+ - Each takes ONE field of base64-encoded image bytes (`image` / `banner`): not a
13
+ URL, not multipart, and NOT a `media_id` from `twitter_media_upload`. Both tool
14
+ descriptions say so in the first two sentences, because a model choosing between
15
+ these and the media-upload tool on the word "upload" alone will get it wrong.
16
+ - Both descriptions also carry the two things a schema cannot: there is NO UNDO
17
+ and the vendor keeps no history, so read and save the current image URL first;
18
+ and confirm a banner write by reading `cover_picture` back specifically, since
19
+ at least one vendor endpoint reports that field as empty for accounts that
20
+ plainly have one.
21
+ - Both are declared `jsonBody`, and here the API's "json-only" classification is
22
+ EXACT rather than conservative: the shared handler reads the JSON body and has
23
+ no query fallback at all, so a query string genuinely cannot work.
24
+
3
25
  ## 0.11.1 (2026-09-13)
4
26
 
5
27
  ### Fixed
package/README.md CHANGED
@@ -91,7 +91,7 @@ Restart Claude Desktop. The `twitter_*` tools appear in the tool picker.
91
91
 
92
92
  ## Tools
93
93
 
94
- 107 tools: 65 reads and 42 write actions. Most user endpoints accept `username` (handle without @) **or** `user_id` (`twitter_user_likes` and `twitter_user_tweets_complete` require `user_id`); tweet endpoints accept `id` **or** `url`; paginated endpoints return a `cursor` you pass back to get the next page. Four of the reads are free account lookups (`twitter_account_me`, `twitter_account_payments`, `twitter_feedback_get`, `twitter_feedback_list`); the 14 monitoring tools and `twitter_feedback_send` are also free (account administration, not metered reads).
94
+ 109 tools: 65 reads and 44 write actions. Most user endpoints accept `username` (handle without @) **or** `user_id` (`twitter_user_likes` and `twitter_user_tweets_complete` require `user_id`); tweet endpoints accept `id` **or** `url`; paginated endpoints return a `cursor` you pass back to get the next page. Four of the reads are free account lookups (`twitter_account_me`, `twitter_account_payments`, `twitter_feedback_get`, `twitter_feedback_list`); the 14 monitoring tools and `twitter_feedback_send` are also free (account administration, not metered reads).
95
95
 
96
96
  Public reads (search, profiles, tweets, followers, likes) work with just your API key. The **account-only** reads (bookmarks, DMs, home timeline, followers-you-know) and **most write actions** act AS an authenticated X account, so they need a session linked to your key first (returns HTTP 409 until then). Link a session either by registering your x.com cookies (`twitter_customer_session`) or by logging in with a username/password (`twitter_user_login`). Alternatively, pass **per-call inline credentials** on any of those tools (`auth_token` + `ct0`, with optional `proxy_url` / `user_agent`) to act AS that account for a single call without pre-registering a session, so one API key can act as many accounts. For write actions, set `proxy_url` to a residential proxy, since X soft-blocks writes that egress from datacenter IPs. Each write tool is annotated `readOnlyHint: false`; reversing actions (delete, unfollow, unlike, unretweet, unbookmark, monitor/webhook delete) are annotated `destructiveHint: true` so MCP clients can prompt before running them. The **monitoring** and **feedback** tools (see below) are the exception: they administer your twitterapis.com account, not an X session, so they need only your API key, no linked session and no inline credentials.
97
97
 
@@ -170,6 +170,8 @@ Public reads (search, profiles, tweets, followers, likes) work with just your AP
170
170
  | `twitter_list_add_member` / `twitter_list_remove_member` | Add / remove one account on a List you own; `member_count` comes back as proof the write landed |
171
171
  | `twitter_media_upload` | Upload a base64 image, returns a `media_id` for `twitter_create_tweet` |
172
172
  | `twitter_update_profile` | Change your own name, bio, location or link. A PARTIAL update: omitted fields keep their values, an empty string clears one |
173
+ | `twitter_update_avatar` | Replace your own profile picture. Takes base64 image bytes in `image`, not a URL and not a `media_id`. No undo, and X keeps no history |
174
+ | `twitter_update_banner` | Replace your own header image. Takes base64 image bytes in `banner`, not a URL and not a `media_id`. No undo, and X keeps no history |
173
175
 
174
176
  ### Drafts and scheduled posts _(require a linked X session)_
175
177
 
@@ -327,7 +329,7 @@ count: 50
327
329
 
328
330
  ## Pricing
329
331
 
330
- Calls are billed to your twitterapis.com account. Most endpoints are $0.0008/call: nearly every read (search, profiles, tweets, followers, likes) plus the simple write actions (like, retweet, bookmark, follow and their undos, delete). At the read rate that works out to $0.04 per 1,000 tweets, since each call returns about 20 tweets. The premium endpoints cost a little more: tweet creation, sending a DM (`twitter_dm_send`), and DM reads (`twitter_dm_list`, `twitter_dm_conversation`) at $0.0016/call, full tweet history (`twitter_user_tweets_complete`) at $0.0024/call, a full tweet thread (`twitter_tweet_thread`) and a Grok answer (`twitter_grok_chat`) at $0.004/call, and the article-editing writes (`twitter_article_create`, `twitter_article_update_title`, `twitter_article_update_cover_media`, `twitter_article_update_content`, `twitter_article_publish`, `twitter_article_unpublish`) at $0.0016. The compose surface is $0.0016 for `twitter_draft_create`, `twitter_draft_edit`, `twitter_scheduled_create` and, note, BOTH LIST READS (`twitter_draft_list`, `twitter_scheduled_list`), which are the two reads that are not at the read rate; `twitter_draft_delete` and `twitter_scheduled_delete` are $0.0008/call, while `twitter_article_get`, `twitter_article_list` and `twitter_article_delete` stay at the standard $0.0008/call. `twitter_update_profile`, the one published profile write, is $0.0016/call. Your first $0.50 is free. See [twitterapis.com/pricing](https://www.twitterapis.com/pricing).
332
+ Calls are billed to your twitterapis.com account. Most endpoints are $0.0008/call: nearly every read (search, profiles, tweets, followers, likes) plus the simple write actions (like, retweet, bookmark, follow and their undos, delete). At the read rate that works out to $0.04 per 1,000 tweets, since each call returns about 20 tweets. The premium endpoints cost a little more: tweet creation, sending a DM (`twitter_dm_send`), and DM reads (`twitter_dm_list`, `twitter_dm_conversation`) at $0.0016/call, full tweet history (`twitter_user_tweets_complete`) at $0.0024/call, a full tweet thread (`twitter_tweet_thread`) and a Grok answer (`twitter_grok_chat`) at $0.004/call, and the article-editing writes (`twitter_article_create`, `twitter_article_update_title`, `twitter_article_update_cover_media`, `twitter_article_update_content`, `twitter_article_publish`, `twitter_article_unpublish`) at $0.0016. The compose surface is $0.0016 for `twitter_draft_create`, `twitter_draft_edit`, `twitter_scheduled_create` and, note, BOTH LIST READS (`twitter_draft_list`, `twitter_scheduled_list`), which are the two reads that are not at the read rate; `twitter_draft_delete` and `twitter_scheduled_delete` are $0.0008/call, while `twitter_article_get`, `twitter_article_list` and `twitter_article_delete` stay at the standard $0.0008/call. The three profile writes (`twitter_update_profile`, `twitter_update_avatar`, `twitter_update_banner`) are $0.0016/call each. Your first $0.50 is free. See [twitterapis.com/pricing](https://www.twitterapis.com/pricing).
331
333
 
332
334
  ## Links
333
335
 
@@ -340,7 +342,7 @@ Calls are billed to your twitterapis.com account. Most endpoints are $0.0008/cal
340
342
 
341
343
  **Do I need an X (Twitter) developer account?** No. Get an API key at [twitterapis.com/signup](https://www.twitterapis.com/signup); there is no application or approval step.
342
344
 
343
- **Is it read-only?** No. 65 read tools work with just your API key; 42 write actions (post, save or schedule a post, like, retweet, follow, DM, media upload, List create/add member/remove member, article create/edit/publish/delete, monitor/webhook create/update/delete, feedback send) act as a linked X account or per-call inline credentials, except monitor/webhook CRUD and feedback, which are account administration and need only your API key.
345
+ **Is it read-only?** No. 65 read tools work with just your API key; 44 write actions (post, save or schedule a post, like, retweet, follow, DM, media upload, profile name/bio/avatar/banner updates, List create/add member/remove member, article create/edit/publish/delete, monitor/webhook create/update/delete, feedback send) act as a linked X account or per-call inline credentials, except monitor/webhook CRUD and feedback, which are account administration and need only your API key.
344
346
 
345
347
  **Which clients are supported?** Claude Desktop, Cursor, Windsurf, and VS Code (Copilot agent mode), or any Model Context Protocol client.
346
348
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@twitterapis/mcp",
3
3
  "mcpName": "io.github.TwitterAPIs/twitterapis-mcp",
4
- "version": "0.11.1",
4
+ "version": "0.12.0",
5
5
  "description": "Official MCP server for twitterapis.com, the Twitter/X API (search, users, followers, tweets, threads, lists, likes, bookmarks, DMs) plus write actions (post/like/retweet/follow) as native tools for Claude, Cursor, and any MCP client.",
6
6
  "repository": {
7
7
  "type": "git",
package/src/tools.js CHANGED
@@ -8,12 +8,12 @@
8
8
  // file in memory and fails if it does not match what is committed, so a hand edit
9
9
  // here is caught rather than shipped.
10
10
  //
11
- // Catalog: 107 tools (65 reads, 42 writes).
11
+ // Catalog: 109 tools (65 reads, 44 writes).
12
12
  //
13
13
  // Each tool maps 1:1 to a REST endpoint at https://api.twitterapis.com. Tool arg
14
14
  // names map 1:1 to endpoint query params (every endpoint, including the POST
15
15
  // write actions, reads its params from the query string), except the per-call
16
- // inline credentials, which travel as x-* request headers, the 12
16
+ // inline credentials, which travel as x-* request headers, the 14
17
17
  // jsonBody tools, whose fields travel in a JSON request body, and any arg listed
18
18
  // in pathParams, which is substituted into the URL path (e.g. {id}) instead. A
19
19
  // tool with `method: "POST"` or `method: "DELETE"` is a write that acts on
@@ -1196,6 +1196,58 @@ export const TOOLS = [
1196
1196
  ),
1197
1197
  },
1198
1198
  },
1199
+ {
1200
+ name: "twitter_update_avatar",
1201
+ path: "/twitter/user/update_avatar",
1202
+ method: "POST",
1203
+ write: true,
1204
+ jsonBody: true,
1205
+ description:
1206
+ "Replace the profile picture on your authenticated account's own X profile. Takes ONE field, image, holding base64-encoded image bytes: not a URL, not multipart, and not a media_id from twitter_media_upload. It writes a real profile and takes effect immediately with NO UNDO, and X keeps no history of the previous picture, so if the old image might be wanted back, read profile_image_url with twitter_user_info and save that file BEFORE calling this. Returns ok. To confirm it applied, read the account back with twitter_user_info: X mints a new media id for every accepted upload, so profile_image_url changes even when the image is byte-identical to the one already in place. Requires an authenticated session behind your key.",
1207
+ shape: {
1208
+ image: z.string().describe(
1209
+ "REQUIRED. Base64-encoded image bytes. Not a URL, not multipart, and not a media_id. banner and data are accepted as aliases for this same field.",
1210
+ ),
1211
+ auth_token: z.string().optional().describe(
1212
+ "Optional. The account's auth_token cookie, to act AS that account for this call (must be paired with ct0). Travels out of band: as the x-auth-token request header on most tools, or inside the JSON request body on the tools that take one. Never a query parameter, so it never reaches a URL or an access log.",
1213
+ ),
1214
+ ct0: z.string().optional().describe(
1215
+ "Optional. The account's ct0 cookie, paired with auth_token. Same transport as auth_token: the x-ct0 request header, or the JSON body on a body-taking tool. Never a query parameter.",
1216
+ ),
1217
+ proxy_url: z.string().optional().describe(
1218
+ "Optional. Residential proxy URL to egress this call through. Recommended for writes: X soft-blocks writes from datacenter IPs as automated. Sent as the x-proxy-url request header, or in the JSON body on a body-taking tool.",
1219
+ ),
1220
+ user_agent: z.string().optional().describe(
1221
+ "Optional. User-Agent string to send for this session. Sent as the x-user-agent request header, or in the JSON body on a body-taking tool.",
1222
+ ),
1223
+ },
1224
+ },
1225
+ {
1226
+ name: "twitter_update_banner",
1227
+ path: "/twitter/user/update_banner",
1228
+ method: "POST",
1229
+ write: true,
1230
+ jsonBody: true,
1231
+ description:
1232
+ "Replace the wide header image on your authenticated account's own X profile. Takes ONE field, banner, holding base64-encoded image bytes: not a URL, not multipart, and not a media_id from twitter_media_upload. X renders the header as a wide strip, so a 3:1 image fills it without cropping. It writes a real profile and takes effect immediately with NO UNDO, and X keeps no history of the previous banner, so if the old image might be wanted back, read cover_picture with twitter_user_info and save that file BEFORE calling this. Returns ok. To confirm it applied, read the account back with twitter_user_info and check cover_picture specifically: at least one of X's own endpoints reports that field as empty for accounts that plainly have a banner, so an empty answer from anywhere else is not evidence the account has none. Requires an authenticated session behind your key.",
1233
+ shape: {
1234
+ banner: z.string().describe(
1235
+ "REQUIRED. Base64-encoded image bytes. Not a URL, not multipart, and not a media_id. image and data are accepted as aliases for this same field.",
1236
+ ),
1237
+ auth_token: z.string().optional().describe(
1238
+ "Optional. The account's auth_token cookie, to act AS that account for this call (must be paired with ct0). Travels out of band: as the x-auth-token request header on most tools, or inside the JSON request body on the tools that take one. Never a query parameter, so it never reaches a URL or an access log.",
1239
+ ),
1240
+ ct0: z.string().optional().describe(
1241
+ "Optional. The account's ct0 cookie, paired with auth_token. Same transport as auth_token: the x-ct0 request header, or the JSON body on a body-taking tool. Never a query parameter.",
1242
+ ),
1243
+ proxy_url: z.string().optional().describe(
1244
+ "Optional. Residential proxy URL to egress this call through. Recommended for writes: X soft-blocks writes from datacenter IPs as automated. Sent as the x-proxy-url request header, or in the JSON body on a body-taking tool.",
1245
+ ),
1246
+ user_agent: z.string().optional().describe(
1247
+ "Optional. User-Agent string to send for this session. Sent as the x-user-agent request header, or in the JSON body on a body-taking tool.",
1248
+ ),
1249
+ },
1250
+ },
1199
1251
  {
1200
1252
  name: "twitter_draft_create",
1201
1253
  path: "/twitter/draft/create",