@twitterapis/mcp 0.6.6 → 0.6.8

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,6 +1,28 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
3
+ ## 0.6.8 (2026-08-10)
4
+
5
+ ### Added
6
+
7
+ - **`twitter_article_get` gains an owner-only `article_id` form** (task #12, competitor parity): pass `article_id` (the article's own entity id, from `twitter_article_create` or `twitter_article_list`) to read one of your own articles by id, including Drafts, which have no announcement tweet the existing public `id`/`url` form could resolve. Requires a registered session or per-call `auth_token`/`ct0`, same as the other authenticated article tools. Returns `article: null` when the id is not found or not owned by the calling account, X exposes no dedicated get-by-id op, so this scans the caller's own Draft then Published lists and matches client-side, same approach `article/delete` already used for lifecycle resolution.
8
+
9
+ ## 0.6.7 (2026-08-10)
10
+
11
+ ### Added
12
+
13
+ - **8 new tools for X's long-form Articles/Notes feature** (#1096): `twitter_article_create`, `twitter_article_update_title`, `twitter_article_update_content`, `twitter_article_publish`, `twitter_article_unpublish`, `twitter_article_get`, `twitter_article_list`, `twitter_article_delete`. `twitter_article_get` is a public read (no session required, like `twitter_tweet_detail`); the other 7 require a customer session. The catalog is now **60 tools: 39 reads and 21 write actions**.
14
+
15
+ ## 0.6.6 (2026-08-09)
16
+
17
+ ### Added
18
+
19
+ - **`twitter_customer_session_delete`**, the self-serve counterpart to `twitter_customer_session`: the backend has shipped this revoke endpoint since PR #188, but no published surface carried it, so an agent could link a session with no documented way to unlink it. Takes no body field and no header beyond the API key; the handler resolves the session to delete from the auth context, which is what makes cross-key deletion impossible. Placed next to `twitter_customer_session` so the way out sits beside the way in. The catalog is now **52 tools: 37 reads and 15 write actions**.
20
+
21
+ ### Fixed
22
+
23
+ - **`twitter_user_login` was missing `proxy_url` and `user_agent`**, which the backend handler reads and stores on the resulting session, governing that session's ongoing egress and fingerprint rather than just the one login call. Both were undocumented and therefore uncallable through the tool. Verified against `src/server/routes/user-login.ts`, not the spec.
24
+
25
+ ## 0.6.5 (2026-08-06)
4
26
 
5
27
  ### Changed
6
28
 
@@ -31,7 +53,7 @@
31
53
 
32
54
  - Release tooling hardened. No user-facing or API behaviour change.
33
55
 
34
- ## Unreleased
56
+ ## 0.6.2 (2026-07-21)
35
57
 
36
58
  ### Added
37
59
 
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
- 52 tools: 37 reads and 15 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. Two of the reads are free account/billing lookups (`twitter_account_me`, `twitter_account_payments`).
94
+ 60 tools: 39 reads and 21 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. Two of the reads are free account/billing lookups (`twitter_account_me`, `twitter_account_payments`).
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 **all 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) are annotated `destructiveHint: true` so MCP clients can prompt before running them.
97
97
 
@@ -136,6 +136,8 @@ Public reads (search, profiles, tweets, followers, likes) work with just your AP
136
136
  | `twitter_account_me` | Your twitterapis.com account: credits, usage, email (free) |
137
137
  | `twitter_account_payments` | Your twitterapis.com payment history (free) |
138
138
  | `twitter_media_status` | Processing state of an uploaded `media_id`; poll until `succeeded` before attaching video or GIF _(session)_ |
139
+ | `twitter_article_get` | Read a **published** article's full content via its announcement tweet id/url (public, no session) |
140
+ | `twitter_article_list` | List your own articles, filtered by `lifecycle` (`draft` or `published`) _(session)_ |
139
141
 
140
142
  ### Write actions _(require a linked X session)_
141
143
 
@@ -150,6 +152,19 @@ Public reads (search, profiles, tweets, followers, likes) work with just your AP
150
152
  | `twitter_dm_send` | Send a Direct Message to a user by their numeric `recipient_id` |
151
153
  | `twitter_media_upload` | Upload a base64 image, returns a `media_id` for `twitter_create_tweet` |
152
154
 
155
+ ### Articles _(X's long-form "Notes" feature; writes require a linked X session)_
156
+
157
+ | Tool | What it does |
158
+ |---|---|
159
+ | `twitter_article_create` | Start a new draft article, returns its `id` |
160
+ | `twitter_article_update_title` | Set a draft or published article's title |
161
+ | `twitter_article_update_content` | Replace a draft or published article's body (Draft.js `content_state` you build) |
162
+ | `twitter_article_publish` | Publish a draft, posting a **real public announcement tweet** (not fully reversible) |
163
+ | `twitter_article_unpublish` | Revert a published article to draft (leaves the announcement tweet up) |
164
+ | `twitter_article_delete` | Delete an article (draft: hard delete; published: unpublish + delete the announcement tweet), irreversible |
165
+
166
+ See also `twitter_article_get` and `twitter_article_list` above.
167
+
153
168
  ### Session setup
154
169
 
155
170
  Link an X account to your key once, so the account-only reads and write actions act as it (or pass per-call `auth_token`/`ct0` instead).
@@ -227,7 +242,7 @@ count: 50
227
242
 
228
243
  ## Pricing
229
244
 
230
- Calls are billed to your twitterapis.com account. Almost every endpoint is $0.0008/call: all reads (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, and a full tweet thread (`twitter_tweet_thread`) at $0.004/call. Your first $0.50 is free. See [twitterapis.com/pricing](https://www.twitterapis.com/pricing).
245
+ Calls are billed to your twitterapis.com account. Almost every endpoint is $0.0008/call: all reads (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`) at $0.004/call, and the article-editing writes (`twitter_article_create`, `twitter_article_update_title`, `twitter_article_update_content`, `twitter_article_publish`, `twitter_article_unpublish`) at $0.0016/call (`twitter_article_get`, `twitter_article_list`, and `twitter_article_delete` stay at the standard $0.0008/call). Your first $0.50 is free. See [twitterapis.com/pricing](https://www.twitterapis.com/pricing).
231
246
 
232
247
  ## Links
233
248
 
@@ -240,7 +255,7 @@ Calls are billed to your twitterapis.com account. Almost every endpoint is $0.00
240
255
 
241
256
  **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.
242
257
 
243
- **Is it read-only?** No. 37 read tools work with just your API key; 15 write actions (post, like, retweet, follow, DM, media upload) act as a linked X account or per-call inline credentials.
258
+ **Is it read-only?** No. 39 read tools work with just your API key; 21 write actions (post, like, retweet, follow, DM, media upload, article create/edit/publish/delete) act as a linked X account or per-call inline credentials.
244
259
 
245
260
  **Which clients are supported?** Claude Desktop, Cursor, Windsurf, and VS Code (Copilot agent mode), or any Model Context Protocol client.
246
261
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twitterapis/mcp",
3
- "version": "0.6.6",
3
+ "version": "0.6.8",
4
4
  "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.",
5
5
  "repository": {
6
6
  "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: 52 tools (37 reads, 15 writes).
11
+ // Catalog: 60 tools (39 reads, 21 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, and the three
16
+ // inline credentials, which travel as x-* request headers, and the 4
17
17
  // jsonBody tools, whose fields travel in a JSON request body. A tool with
18
18
  // `method: "POST"` is a write that acts on behalf of the authenticated account
19
19
  // behind your API key; reads are GET and default when `method` is omitted.
@@ -997,7 +997,7 @@ export const TOOLS = [
997
997
  write: true,
998
998
  jsonBody: true,
999
999
  description:
1000
- "Register YOUR OWN X account session against your API key, so the authenticated-account tools (twitter_home_timeline, twitter_bookmarks, twitter_dm_list, twitter_dm_conversation, twitter_user_likes) and the write tools (twitter_create_tweet, twitter_dm_send, twitter_follow_user, twitter_favorite_tweet, twitter_retweet, twitter_media_upload) act as your account. Provide your x.com session cookies auth_token and ct0 (copy them from a logged-in browser); optionally a user_agent and a residential proxy_url. The cookies are stored server-side against your key and are never returned. Returns ok, the resolved username, and whether the session validated live. Prefer twitter_user_login if you would rather pass a username/password than raw cookies. Most tools also accept auth_token/ct0 per-call without registering.",
1000
+ "Register YOUR OWN X account session against your API key, so the authenticated-account tools (twitter_home_timeline, twitter_bookmarks, twitter_dm_list, twitter_dm_conversation, twitter_user_likes, twitter_article_list) and the write tools (twitter_create_tweet, twitter_dm_send, twitter_follow_user, twitter_favorite_tweet, twitter_retweet, twitter_media_upload, twitter_article_create, twitter_article_update_title, twitter_article_update_content, twitter_article_publish, twitter_article_unpublish, twitter_article_delete) act as your account. Provide your x.com session cookies auth_token and ct0 (copy them from a logged-in browser); optionally a user_agent and a residential proxy_url. The cookies are stored server-side against your key and are never returned. Returns ok, the resolved username, and whether the session validated live. Prefer twitter_user_login if you would rather pass a username/password than raw cookies. Most tools also accept auth_token/ct0 per-call without registering.",
1001
1001
  shape: {
1002
1002
  auth_token: z.string().describe(
1003
1003
  "Your x.com auth_token cookie value, from a logged-in browser session. Stored server-side against your key; never returned.",
@@ -1097,6 +1097,235 @@ export const TOOLS = [
1097
1097
  ),
1098
1098
  },
1099
1099
  },
1100
+ {
1101
+ name: "twitter_article_create",
1102
+ path: "/twitter/article/create",
1103
+ method: "POST",
1104
+ write: true,
1105
+ description:
1106
+ "Start a new DRAFT article ('Note') AS your authenticated account. No input required. Returns the new article's id (pass this to twitter_article_update_title / twitter_article_update_content / twitter_article_publish / twitter_article_delete) and its full article object. Requires an authenticated session with write capability behind your key.",
1107
+ shape: {
1108
+ auth_token: z.string().optional().describe(
1109
+ "Optional. The account's auth_token cookie, to act AS that account for this call (must be paired with ct0). Sent as the x-auth-token header; never placed in the URL.",
1110
+ ),
1111
+ ct0: z.string().optional().describe(
1112
+ "Optional. The account's ct0 cookie, paired with auth_token. Sent as the x-ct0 header.",
1113
+ ),
1114
+ proxy_url: z.string().optional().describe(
1115
+ "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 header.",
1116
+ ),
1117
+ user_agent: z.string().optional().describe(
1118
+ "Optional. User-Agent string to send for this session. Sent as the x-user-agent header.",
1119
+ ),
1120
+ },
1121
+ },
1122
+ {
1123
+ name: "twitter_article_update_title",
1124
+ path: "/twitter/article/update_title",
1125
+ method: "POST",
1126
+ write: true,
1127
+ description:
1128
+ "Set or replace the title of a DRAFT or PUBLISHED article AS your authenticated account. Provide the article's id (from twitter_article_create or twitter_article_list) and the new title. Requires an authenticated session with write capability behind your key. Returns the updated article object.",
1129
+ shape: {
1130
+ id: z.string().describe(
1131
+ "The article's entity id, from twitter_article_create or twitter_article_list (e.g. 'ArticleEntity:1234567890123456789').",
1132
+ ),
1133
+ title: z.string().min(1).describe(
1134
+ "The new article title (non-empty).",
1135
+ ),
1136
+ auth_token: z.string().optional().describe(
1137
+ "Optional. The account's auth_token cookie, to act AS that account for this call (must be paired with ct0). Sent as the x-auth-token header; never placed in the URL.",
1138
+ ),
1139
+ ct0: z.string().optional().describe(
1140
+ "Optional. The account's ct0 cookie, paired with auth_token. Sent as the x-ct0 header.",
1141
+ ),
1142
+ proxy_url: z.string().optional().describe(
1143
+ "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 header.",
1144
+ ),
1145
+ user_agent: z.string().optional().describe(
1146
+ "Optional. User-Agent string to send for this session. Sent as the x-user-agent header.",
1147
+ ),
1148
+ },
1149
+ },
1150
+ {
1151
+ name: "twitter_article_update_content",
1152
+ path: "/twitter/article/update_content",
1153
+ method: "POST",
1154
+ write: true,
1155
+ jsonBody: true,
1156
+ description:
1157
+ "Replace the body content of a DRAFT or PUBLISHED article AS your authenticated account. Provide the article's id and content_state: Draft.js JSON ({ blocks: [...], entityMap: [...] }) that YOU build and pass through verbatim, this tool does not construct or validate it. Requires an authenticated session with write capability behind your key. Returns the updated article object.",
1158
+ shape: {
1159
+ id: z.string().describe(
1160
+ "The article's entity id, from twitter_article_create or twitter_article_list.",
1161
+ ),
1162
+ content_state: z.record(z.string(), z.unknown()).describe(
1163
+ "Draft.js content state object: { blocks: [...], entityMap: [...] }. You construct this JSON yourself (it is the same shape the X Article editor produces); it is passed through to X verbatim and not validated here.",
1164
+ ),
1165
+ auth_token: z.string().optional().describe(
1166
+ "Optional. The account's auth_token cookie, to act AS that account for this call (must be paired with ct0). Sent as the x-auth-token header; never placed in the URL.",
1167
+ ),
1168
+ ct0: z.string().optional().describe(
1169
+ "Optional. The account's ct0 cookie, paired with auth_token. Sent as the x-ct0 header.",
1170
+ ),
1171
+ proxy_url: z.string().optional().describe(
1172
+ "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 header.",
1173
+ ),
1174
+ user_agent: z.string().optional().describe(
1175
+ "Optional. User-Agent string to send for this session. Sent as the x-user-agent header.",
1176
+ ),
1177
+ },
1178
+ },
1179
+ {
1180
+ name: "twitter_article_publish",
1181
+ path: "/twitter/article/publish",
1182
+ method: "POST",
1183
+ write: true,
1184
+ description:
1185
+ "Publish a DRAFT article AS your authenticated account, transitioning it to Published and posting a REAL, PUBLIC announcement tweet that your followers and anyone with the link can see. WARNING: this is a genuinely consequential, hard-to-fully-undo action, it is not like saving a draft. twitter_article_unpublish reverts the article to Draft but LEAVES the announcement tweet up; only twitter_article_delete on a published article unpublishes AND removes the announcement tweet, and by then the content was already public for however long it stayed up. Confirm with the caller before publishing unless they have clearly asked for it. Provide the article's id; audience and reply_control default to 'Everyone' when omitted; caption is an optional short (<=256 character) caption for the announcement tweet. Requires an authenticated session with write capability behind your key. Returns the updated (Published) article object.",
1186
+ shape: {
1187
+ id: z.string().describe(
1188
+ "The article's entity id, from twitter_article_create or twitter_article_list. Must currently be a Draft.",
1189
+ ),
1190
+ audience: z.string().optional().describe(
1191
+ "Optional. Who can see the published article, e.g. 'Everyone'. Defaults to 'Everyone' when omitted.",
1192
+ ),
1193
+ reply_control: z.string().optional().describe(
1194
+ "Optional. Who can reply to the announcement tweet, e.g. 'Everyone'. Defaults to 'Everyone' when omitted.",
1195
+ ),
1196
+ caption: z.string().optional().describe(
1197
+ "Optional. Short caption text for the announcement tweet, up to 256 characters.",
1198
+ ),
1199
+ auth_token: z.string().optional().describe(
1200
+ "Optional. The account's auth_token cookie, to act AS that account for this call (must be paired with ct0). Sent as the x-auth-token header; never placed in the URL.",
1201
+ ),
1202
+ ct0: z.string().optional().describe(
1203
+ "Optional. The account's ct0 cookie, paired with auth_token. Sent as the x-ct0 header.",
1204
+ ),
1205
+ proxy_url: z.string().optional().describe(
1206
+ "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 header.",
1207
+ ),
1208
+ user_agent: z.string().optional().describe(
1209
+ "Optional. User-Agent string to send for this session. Sent as the x-user-agent header.",
1210
+ ),
1211
+ },
1212
+ },
1213
+ {
1214
+ name: "twitter_article_unpublish",
1215
+ path: "/twitter/article/unpublish",
1216
+ method: "POST",
1217
+ write: true,
1218
+ destructive: true,
1219
+ description:
1220
+ "Revert a PUBLISHED article back to Draft AS your authenticated account. The announcement tweet the publish posted is LEFT IN PLACE, still publicly visible, use twitter_article_delete instead if you also want that tweet removed. X refuses this with an 'invalid_lifecycle' error if the article is not currently Published. Requires an authenticated session with write capability behind your key. Returns the updated (Draft) article object.",
1221
+ shape: {
1222
+ id: z.string().describe(
1223
+ "The article's entity id, from twitter_article_create or twitter_article_list. Must currently be Published.",
1224
+ ),
1225
+ auth_token: z.string().optional().describe(
1226
+ "Optional. The account's auth_token cookie, to act AS that account for this call (must be paired with ct0). Sent as the x-auth-token header; never placed in the URL.",
1227
+ ),
1228
+ ct0: z.string().optional().describe(
1229
+ "Optional. The account's ct0 cookie, paired with auth_token. Sent as the x-ct0 header.",
1230
+ ),
1231
+ proxy_url: z.string().optional().describe(
1232
+ "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 header.",
1233
+ ),
1234
+ user_agent: z.string().optional().describe(
1235
+ "Optional. User-Agent string to send for this session. Sent as the x-user-agent header.",
1236
+ ),
1237
+ },
1238
+ },
1239
+ {
1240
+ name: "twitter_article_get",
1241
+ path: "/twitter/article/get",
1242
+ description:
1243
+ "Read an article's full content (title, content_state, cover media, author, timestamps, public_url). Two mutually exclusive forms. PUBLIC: provide id or url of the article's announcement tweet, no registered session or per-call credentials needed, just your API key, same auth model as twitter_tweet_detail, works for PUBLISHED articles only. OWNER-ONLY: provide article_id (the article's own entity id, from twitter_article_create or twitter_article_list), requires an authenticated session, also reaches your own Drafts, which have no announcement tweet the public form could resolve. Returns 404 (article null) if not found, not visible, or (article_id form) not owned by the calling account.",
1244
+ shape: {
1245
+ id: z.string().optional().describe(
1246
+ "Tweet/post numeric id (e.g. \"1789012345678901234\"). Provide exactly one of id or url.",
1247
+ ),
1248
+ url: z.string().optional().describe(
1249
+ "Full tweet URL, e.g. \"https://x.com/elonmusk/status/1789012345678901234\". Provide exactly one of id or url.",
1250
+ ),
1251
+ article_id: z.string().optional().describe(
1252
+ "OWNER-ONLY form. The article's own entity id, from twitter_article_create or twitter_article_list (e.g. 'ArticleEntity:1234567890123456789', or the bare numeric rest_id). Requires an authenticated session. Provide exactly one of id, url, or article_id.",
1253
+ ),
1254
+ auth_token: z.string().optional().describe(
1255
+ "Optional. The account's auth_token cookie, to act AS that account for this call (must be paired with ct0). Sent as the x-auth-token header; never placed in the URL.",
1256
+ ),
1257
+ ct0: z.string().optional().describe(
1258
+ "Optional. The account's ct0 cookie, paired with auth_token. Sent as the x-ct0 header.",
1259
+ ),
1260
+ proxy_url: z.string().optional().describe(
1261
+ "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 header.",
1262
+ ),
1263
+ user_agent: z.string().optional().describe(
1264
+ "Optional. User-Agent string to send for this session. Sent as the x-user-agent header.",
1265
+ ),
1266
+ },
1267
+ },
1268
+ {
1269
+ name: "twitter_article_list",
1270
+ path: "/twitter/article/list",
1271
+ description:
1272
+ "List YOUR OWN articles (drafts or published) AS your authenticated account, most recent first. X exposes no combined view, so this filters to ONE lifecycle per call: pass lifecycle='published' to list published articles, omit it (or pass 'draft') for drafts. Requires an authenticated session behind your key. Returns count, next_cursor (pass it back as cursor to fetch the next page; null/absent means no more pages), and the page of article objects.",
1273
+ shape: {
1274
+ lifecycle: z.enum(["draft","published"]).optional().describe(
1275
+ "Which lifecycle to list: 'draft' or 'published'. Defaults to 'draft' when omitted. X has no combined view, list each lifecycle separately.",
1276
+ ),
1277
+ count: z.number().int().min(1).max(100).optional().describe(
1278
+ "Max articles to return for this page, 1 to 100. Defaults to 20 when omitted.",
1279
+ ),
1280
+ cursor: z.string().optional().describe(
1281
+ "Opaque pagination cursor from a previous response's next_cursor field. Omit on the first call; pass on subsequent calls to fetch the next page.",
1282
+ ),
1283
+ auth_token: z.string().optional().describe(
1284
+ "Optional. The account's auth_token cookie, to act AS that account for this call (must be paired with ct0). Sent as the x-auth-token header; never placed in the URL.",
1285
+ ),
1286
+ ct0: z.string().optional().describe(
1287
+ "Optional. The account's ct0 cookie, paired with auth_token. Sent as the x-ct0 header.",
1288
+ ),
1289
+ proxy_url: z.string().optional().describe(
1290
+ "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 header.",
1291
+ ),
1292
+ user_agent: z.string().optional().describe(
1293
+ "Optional. User-Agent string to send for this session. Sent as the x-user-agent header.",
1294
+ ),
1295
+ },
1296
+ },
1297
+ {
1298
+ name: "twitter_article_delete",
1299
+ path: "/twitter/article/delete",
1300
+ method: "POST",
1301
+ write: true,
1302
+ destructive: true,
1303
+ description:
1304
+ "Delete an article AS your authenticated account. A DRAFT is hard-deleted outright; a PUBLISHED article is unpublished first and then its announcement tweet is deleted too, so this is the one op that fully removes a published article's public footprint (compare twitter_article_unpublish, which leaves the tweet up). Irreversible. lifecycle and tweet_id are optional fast-path hints (read them off a prior twitter_article_create or twitter_article_list response): when omitted, the server figures out the lifecycle itself by scanning your own Draft then Published articles, which costs an extra round trip. Requires an authenticated session with write capability behind your key. Returns ok/deleted and the id you targeted.",
1305
+ shape: {
1306
+ id: z.string().describe(
1307
+ "The article's entity id, from twitter_article_create or twitter_article_list.",
1308
+ ),
1309
+ lifecycle: z.enum(["draft","published"]).optional().describe(
1310
+ "Optional fast-path hint: 'draft' or 'published', if you already know it. Omit to let the server resolve it (slower, one extra lookup).",
1311
+ ),
1312
+ tweet_id: z.string().optional().describe(
1313
+ "Optional fast-path hint: the announcement tweet id, only meaningful when lifecycle is 'published'. Omit to let the server resolve it from your own article list.",
1314
+ ),
1315
+ auth_token: z.string().optional().describe(
1316
+ "Optional. The account's auth_token cookie, to act AS that account for this call (must be paired with ct0). Sent as the x-auth-token header; never placed in the URL.",
1317
+ ),
1318
+ ct0: z.string().optional().describe(
1319
+ "Optional. The account's ct0 cookie, paired with auth_token. Sent as the x-ct0 header.",
1320
+ ),
1321
+ proxy_url: z.string().optional().describe(
1322
+ "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 header.",
1323
+ ),
1324
+ user_agent: z.string().optional().describe(
1325
+ "Optional. User-Agent string to send for this session. Sent as the x-user-agent header.",
1326
+ ),
1327
+ },
1328
+ },
1100
1329
  ];
1101
1330
 
1102
1331
  // The query-string builder is hand-written logic, not catalog data, so it lives