@twitterapis/mcp 0.1.1 → 0.2.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 +14 -0
- package/README.md +30 -4
- package/package.json +2 -2
- package/src/index.js +28 -12
- package/src/tools.js +274 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0 (2026-06-25)
|
|
4
|
+
|
|
5
|
+
### Added (full API parity)
|
|
6
|
+
|
|
7
|
+
- Grew the catalog from 16 to **37 tools**: 27 reads and 10 write actions.
|
|
8
|
+
- New reads: `twitter_user_about`, `twitter_user_affiliates`, `twitter_check_follow_relationship`, `twitter_user_tweets_complete`, `twitter_user_likes`, `twitter_followers_you_know`, `twitter_home_timeline`, `twitter_bookmarks`, `twitter_bookmark_search`, `twitter_dm_list`, `twitter_dm_conversation`.
|
|
9
|
+
- New write actions: `twitter_create_tweet` (with `reply_to` / `quote`), `twitter_delete_tweet`, `twitter_favorite_tweet` / `twitter_unfavorite_tweet`, `twitter_retweet` / `twitter_unretweet`, `twitter_bookmark_tweet` / `twitter_unbookmark_tweet`, `twitter_follow_user` / `twitter_unfollow_user`.
|
|
10
|
+
- Tool annotations: every write is `readOnlyHint: false`; reversing actions (delete, unfollow, unlike, unretweet, unbookmark) are `destructiveHint: true` so MCP clients can prompt before a mutating call.
|
|
11
|
+
- Account-only reads and all writes act AS a linked X session; added an HTTP 409 error hint pointing users to link a session.
|
|
12
|
+
|
|
13
|
+
### No breaking changes
|
|
14
|
+
|
|
15
|
+
All 16 prior tool names, parameter names, and endpoint mappings are unchanged. Existing `npx @twitterapis/mcp@latest` invocations update automatically.
|
|
16
|
+
|
|
3
17
|
## 0.1.1 (2026-06-24)
|
|
4
18
|
|
|
5
19
|
### Improvements
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @twitterapis/mcp
|
|
2
2
|
|
|
3
|
-
Official **Model Context Protocol** server for [twitterapis.com](https://www.twitterapis.com), the Twitter / X
|
|
3
|
+
Official **Model Context Protocol** server for [twitterapis.com](https://www.twitterapis.com), the Twitter / X API as native tools for Claude, Cursor, Windsurf, and any MCP client. Reads (search, profiles, timelines, followers, DMs) plus write actions (post, like, retweet, follow).
|
|
4
4
|
|
|
5
5
|
Ask your agent to search tweets, pull a user's profile or timeline, list followers/following, fetch thread context, or enumerate list members and it calls the API directly. Every tool maps to a REST endpoint at `https://api.twitterapis.com`; the server holds no state and forwards your API key on each call.
|
|
6
6
|
|
|
@@ -87,7 +87,11 @@ Restart Claude Desktop. The `twitter_*` tools appear in the tool picker.
|
|
|
87
87
|
|
|
88
88
|
## Tools
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
37 tools: 27 reads and 10 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.
|
|
91
|
+
|
|
92
|
+
Public reads (search, profiles, tweets, followers) work with just your API key. The **account-only** reads (likes, 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). 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.
|
|
93
|
+
|
|
94
|
+
### Reads
|
|
91
95
|
|
|
92
96
|
| Tool | What it does |
|
|
93
97
|
|---|---|
|
|
@@ -95,18 +99,40 @@ All 16 tools are read-only. User endpoints accept `username` (handle without @)
|
|
|
95
99
|
| `twitter_user_search` | Find user accounts by name or keyword |
|
|
96
100
|
| `twitter_user_info` | Full profile by handle (bio, counts, verification, location) |
|
|
97
101
|
| `twitter_user_info_by_id` | Full profile by numeric user id |
|
|
102
|
+
| `twitter_user_about` | A user's structured About panel (category, professional labels, joined date) |
|
|
103
|
+
| `twitter_user_affiliates` | Accounts affiliated with an organization profile |
|
|
104
|
+
| `twitter_check_follow_relationship` | Follow relationship between two user ids (who follows whom) |
|
|
98
105
|
| `twitter_user_tweets` | A user's recent original tweets (replies excluded) |
|
|
99
106
|
| `twitter_user_tweets_and_replies` | A user's full timeline (tweets + replies) |
|
|
107
|
+
| `twitter_user_tweets_complete` | A user's near-complete tweet history in one auto-paginated call |
|
|
108
|
+
| `twitter_user_media` | Images and videos a user has posted |
|
|
109
|
+
| `twitter_user_mentions` | Recent public tweets mentioning a user |
|
|
110
|
+
| `twitter_user_likes` | Tweets a user has liked (public Likes tab) |
|
|
100
111
|
| `twitter_user_followers` | Accounts that follow a user |
|
|
101
112
|
| `twitter_user_following` | Accounts a user follows |
|
|
102
113
|
| `twitter_user_verified_followers` | A user's verified followers only |
|
|
103
|
-
| `
|
|
104
|
-
| `twitter_user_mentions` | Recent public tweets mentioning a user |
|
|
114
|
+
| `twitter_followers_you_know` | Followers of a target that your authenticated account also follows |
|
|
105
115
|
| `twitter_tweet_detail` | Single tweet: text, author, metrics, media, quoted/reply context |
|
|
106
116
|
| `twitter_tweet_replies` | Replies to a tweet |
|
|
107
117
|
| `twitter_tweet_thread` | Full author thread (connected tweet chain by same author) |
|
|
108
118
|
| `twitter_tweet_retweeters` | Accounts that retweeted a tweet |
|
|
109
119
|
| `twitter_list_members` | Members of a Twitter/X List |
|
|
120
|
+
| `twitter_home_timeline` | Your authenticated account's Home timeline _(session)_ |
|
|
121
|
+
| `twitter_bookmarks` | Your authenticated account's bookmarks _(session)_ |
|
|
122
|
+
| `twitter_bookmark_search` | Full-text search within your bookmarks _(session)_ |
|
|
123
|
+
| `twitter_dm_list` | Your DM conversations (inbox), read-only _(session)_ |
|
|
124
|
+
| `twitter_dm_conversation` | Messages in one DM conversation, read-only _(session)_ |
|
|
125
|
+
|
|
126
|
+
### Write actions _(require a linked X session)_
|
|
127
|
+
|
|
128
|
+
| Tool | What it does |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `twitter_create_tweet` | Post a tweet; set `reply_to` to reply or `quote` to quote-tweet |
|
|
131
|
+
| `twitter_delete_tweet` | Delete one of your tweets (irreversible) |
|
|
132
|
+
| `twitter_favorite_tweet` / `twitter_unfavorite_tweet` | Like / unlike a tweet |
|
|
133
|
+
| `twitter_retweet` / `twitter_unretweet` | Retweet / undo retweet |
|
|
134
|
+
| `twitter_bookmark_tweet` / `twitter_unbookmark_tweet` | Bookmark / remove bookmark |
|
|
135
|
+
| `twitter_follow_user` / `twitter_unfollow_user` | Follow / unfollow a user by id |
|
|
110
136
|
|
|
111
137
|
## Usage examples
|
|
112
138
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twitterapis/mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Official MCP server for twitterapis.com, the Twitter/X
|
|
3
|
+
"version": "0.2.0",
|
|
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",
|
|
7
7
|
"url": "https://github.com/TwitterAPIs/twitterapis-mcp.git"
|
package/src/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// @twitterapis/mcp, official MCP server for twitterapis.com
|
|
3
3
|
//
|
|
4
|
-
// Exposes the Twitter / X
|
|
5
|
-
// followers/following, tweets, threads,
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
4
|
+
// Exposes the Twitter / X API as native MCP tools for Claude, Cursor, and any
|
|
5
|
+
// MCP client: reads (search, users, followers/following, tweets, threads,
|
|
6
|
+
// lists, mentions, likes, bookmarks, DMs, home timeline) plus write actions
|
|
7
|
+
// (post/delete tweet, like, retweet, bookmark, follow, and their inverses).
|
|
8
|
+
// Each tool is a thin, typed wrapper over a REST endpoint at
|
|
9
|
+
// https://api.twitterapis.com. The server holds no state and forwards your API
|
|
10
|
+
// key on every call. The tool catalog lives in ./tools.js.
|
|
9
11
|
//
|
|
10
12
|
// Config (env):
|
|
11
13
|
// TWITTERAPIS_KEY required. Your key from https://www.twitterapis.com/signup
|
|
@@ -32,7 +34,10 @@ if (!API_KEY) {
|
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
// ── REST call ────────────────────────────────────────────────────────────────
|
|
35
|
-
|
|
37
|
+
// Every endpoint (GET reads and POST writes alike) reads its params from the
|
|
38
|
+
// query string, so the same buildQuery path serves both; only the HTTP method
|
|
39
|
+
// differs per tool.
|
|
40
|
+
async function callEndpoint(path, args, method = "GET") {
|
|
36
41
|
const q = buildQuery(args);
|
|
37
42
|
const url = `${BASE_URL}${path}${q ? `?${q}` : ""}`;
|
|
38
43
|
|
|
@@ -40,13 +45,13 @@ async function callEndpoint(path, args) {
|
|
|
40
45
|
const timer = setTimeout(() => ctrl.abort(), REQUEST_TIMEOUT_MS);
|
|
41
46
|
try {
|
|
42
47
|
const res = await fetch(url, {
|
|
43
|
-
method
|
|
48
|
+
method,
|
|
44
49
|
headers: {
|
|
45
50
|
// The API accepts either header; send both for maximum compatibility.
|
|
46
51
|
Authorization: `Bearer ${API_KEY}`,
|
|
47
52
|
"x-api-key": API_KEY,
|
|
48
53
|
accept: "application/json",
|
|
49
|
-
"user-agent": "twitterapis-mcp/0.
|
|
54
|
+
"user-agent": "twitterapis-mcp/0.2.0",
|
|
50
55
|
},
|
|
51
56
|
signal: ctrl.signal,
|
|
52
57
|
});
|
|
@@ -61,7 +66,9 @@ async function callEndpoint(path, args) {
|
|
|
61
66
|
? " (access forbidden. The resource may be private or your plan does not include this endpoint)"
|
|
62
67
|
: res.status === 404
|
|
63
68
|
? " (not found. The user, tweet, or list may have been deleted or the id is wrong)"
|
|
64
|
-
: res.status ===
|
|
69
|
+
: res.status === 409
|
|
70
|
+
? " (no authenticated X session for this key. Write actions and account-only reads (likes, bookmarks, DMs, home timeline, follow, post) require linking an X account/session to your key first; see https://www.twitterapis.com/dashboard)"
|
|
71
|
+
: res.status === 429
|
|
65
72
|
? " (rate limited. Wait a few seconds and retry; reduce request frequency or increase TWITTERAPIS_TIMEOUT_MS if needed)"
|
|
66
73
|
: res.status >= 500
|
|
67
74
|
? " (upstream API error. Retry in a moment; if persistent, check https://www.twitterapis.com/status)"
|
|
@@ -78,13 +85,22 @@ async function callEndpoint(path, args) {
|
|
|
78
85
|
}
|
|
79
86
|
|
|
80
87
|
// ── MCP server ───────────────────────────────────────────────────────────────
|
|
81
|
-
const server = new McpServer({ name: "twitterapis", version: "0.
|
|
88
|
+
const server = new McpServer({ name: "twitterapis", version: "0.2.0" });
|
|
82
89
|
|
|
83
90
|
for (const tool of TOOLS) {
|
|
91
|
+
const method = tool.method || "GET";
|
|
92
|
+
// Surface read/write/destructive intent so MCP clients can warn before a
|
|
93
|
+
// mutating call (default = read-only).
|
|
94
|
+
const annotations = {
|
|
95
|
+
title: tool.name,
|
|
96
|
+
readOnlyHint: !tool.write,
|
|
97
|
+
destructiveHint: Boolean(tool.destructive),
|
|
98
|
+
openWorldHint: true,
|
|
99
|
+
};
|
|
84
100
|
server.registerTool(
|
|
85
101
|
tool.name,
|
|
86
|
-
{ description: tool.description, inputSchema: tool.shape },
|
|
87
|
-
async (args) => callEndpoint(tool.path, args),
|
|
102
|
+
{ description: tool.description, inputSchema: tool.shape, annotations },
|
|
103
|
+
async (args) => callEndpoint(tool.path, args, method),
|
|
88
104
|
);
|
|
89
105
|
}
|
|
90
106
|
|
package/src/tools.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
// Tool catalog + pure query-builder for @twitterapis/mcp.
|
|
2
2
|
// Kept separate from the server wiring (index.js) so it can be unit-tested
|
|
3
3
|
// without spawning the stdio transport.
|
|
4
|
+
//
|
|
5
|
+
// Each tool maps 1:1 to a REST endpoint at https://api.twitterapis.com. Tool
|
|
6
|
+
// arg names map 1:1 to endpoint query params (every endpoint, including the
|
|
7
|
+
// POST write actions, reads its params from the query string). A tool with
|
|
8
|
+
// `method: "POST"` is a write that acts on behalf of the authenticated account
|
|
9
|
+
// behind your API key; reads are GET and default when `method` is omitted.
|
|
4
10
|
import { z } from "zod";
|
|
5
11
|
|
|
6
12
|
// ── Shared Zod input-schema fragments ───────────────────────────────────────
|
|
@@ -28,9 +34,20 @@ const TWEET_REF = {
|
|
|
28
34
|
'Full tweet URL, e.g. "https://x.com/elonmusk/status/1789012345678901234". Provide exactly one of id or url.',
|
|
29
35
|
),
|
|
30
36
|
};
|
|
37
|
+
// Optional pooled-session selector, shared by every write action. A customer
|
|
38
|
+
// key maps to a default authenticated session; pass account only to target a
|
|
39
|
+
// specific handle in a multi-account pool.
|
|
40
|
+
const ACCOUNT = {
|
|
41
|
+
account: z.string().optional().describe(
|
|
42
|
+
"Optional. The @handle (without @) of the authenticated account to act AS, when your key manages more than one session. Omit to use your key's default session.",
|
|
43
|
+
),
|
|
44
|
+
};
|
|
31
45
|
|
|
32
|
-
// ──
|
|
46
|
+
// ── Tool catalog. Reads are GET (default); writes set method:"POST". ─────────
|
|
47
|
+
// write:true -> action mutates account/Twitter state (annotated readOnlyHint:false)
|
|
48
|
+
// destructive:true -> action removes/reverses state (delete, un-follow/like/RT/bookmark)
|
|
33
49
|
export const TOOLS = [
|
|
50
|
+
// ── Reads: search + discovery ──────────────────────────────────────────────
|
|
34
51
|
{
|
|
35
52
|
name: "twitter_advanced_search",
|
|
36
53
|
path: "/twitter/tweet/advanced_search",
|
|
@@ -80,11 +97,46 @@ export const TOOLS = [
|
|
|
80
97
|
),
|
|
81
98
|
},
|
|
82
99
|
},
|
|
100
|
+
{
|
|
101
|
+
name: "twitter_user_about",
|
|
102
|
+
path: "/twitter/user/user_about",
|
|
103
|
+
description:
|
|
104
|
+
"Get a user's 'About' panel: the structured profile facts X surfaces beyond the bio, such as account category, professional/business labels, joined date, and location when present. Provide a username or a user_id. Use this to enrich a profile beyond what twitter_user_info returns.",
|
|
105
|
+
shape: { ...USER_REF },
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: "twitter_user_affiliates",
|
|
109
|
+
path: "/twitter/user/affiliates",
|
|
110
|
+
description:
|
|
111
|
+
"List the affiliated accounts of an organization profile (the smaller accounts X displays under a company's 'Affiliated' badge, e.g. employees or sub-brands). Provide a username or user_id. Returns profile data per affiliate plus a pagination cursor. Returns empty for accounts with no affiliations.",
|
|
112
|
+
shape: {
|
|
113
|
+
...USER_REF,
|
|
114
|
+
team: z.string().optional().describe(
|
|
115
|
+
"Optional team/sub-group name to filter affiliates by, when the org exposes named teams.",
|
|
116
|
+
),
|
|
117
|
+
...PAGINATION,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: "twitter_check_follow_relationship",
|
|
122
|
+
path: "/twitter/user/check_follow_relationship",
|
|
123
|
+
description:
|
|
124
|
+
"Check the follow relationship between two accounts by numeric user id: whether the source follows the target, whether the target follows the source, blocking/muting flags where available. Both ids are required. Use this to verify a follow before/after a follow action, or to detect mutuals.",
|
|
125
|
+
shape: {
|
|
126
|
+
source_user_id: z.string().describe(
|
|
127
|
+
"Numeric user id of the SOURCE account (the 'is this account following...' subject).",
|
|
128
|
+
),
|
|
129
|
+
target_user_id: z.string().describe(
|
|
130
|
+
"Numeric user id of the TARGET account (the '...the target?' object).",
|
|
131
|
+
),
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
// ── Reads: a user's tweets / timeline ──────────────────────────────────────
|
|
83
135
|
{
|
|
84
136
|
name: "twitter_user_tweets",
|
|
85
137
|
path: "/twitter/user/tweets",
|
|
86
138
|
description:
|
|
87
|
-
"Get a user's recent original tweets, excluding replies and retweets. Returns tweet text, id, timestamp, and engagement metrics. Paginate with cursor to go further back. Use this to analyse a user's own content, opinions, or posting cadence. For replies too, use twitter_user_tweets_and_replies.",
|
|
139
|
+
"Get a user's recent original tweets, excluding replies and retweets. Returns tweet text, id, timestamp, and engagement metrics. Paginate with cursor to go further back. Use this to analyse a user's own content, opinions, or posting cadence. For replies too, use twitter_user_tweets_and_replies; for the full back-catalogue in one call, use twitter_user_tweets_complete.",
|
|
88
140
|
shape: { ...USER_REF, ...PAGINATION },
|
|
89
141
|
},
|
|
90
142
|
{
|
|
@@ -94,6 +146,52 @@ export const TOOLS = [
|
|
|
94
146
|
"Get a user's full activity timeline: their original tweets AND replies to others. Useful for understanding how someone engages with a community, not just what they post. Paginate with cursor. To see only original tweets, use twitter_user_tweets.",
|
|
95
147
|
shape: { ...USER_REF, ...PAGINATION },
|
|
96
148
|
},
|
|
149
|
+
{
|
|
150
|
+
name: "twitter_user_tweets_complete",
|
|
151
|
+
path: "/twitter/user/tweets/complete",
|
|
152
|
+
description:
|
|
153
|
+
"Get a user's near-complete original-tweet history in a single call, auto-paginating server-side up to a cap (Twitter's ~3200-tweet per-user ceiling). Heavier than twitter_user_tweets; use when you want the whole back-catalogue at once rather than page-by-page. Returns a flat tweet array. Requires the numeric user_id (resolve a handle first with twitter_user_info).",
|
|
154
|
+
shape: {
|
|
155
|
+
user_id: z.string().describe(
|
|
156
|
+
"Numeric Twitter/X user id. Required: this endpoint does not accept a username. Resolve a handle to a user_id first with twitter_user_info.",
|
|
157
|
+
),
|
|
158
|
+
max: z.number().int().min(1).max(3200).optional().describe(
|
|
159
|
+
"Maximum number of tweets to collect (default 800, hard ceiling 3200). Higher values take longer and cost more.",
|
|
160
|
+
),
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: "twitter_user_media",
|
|
165
|
+
path: "/twitter/user/media",
|
|
166
|
+
description:
|
|
167
|
+
"Get the images and videos a user has posted. Returns media-containing tweets with URLs to the media files, dimensions, and type (photo/video/animated_gif). Paginate with cursor. Use this to pull a user's visual content history.",
|
|
168
|
+
shape: { ...USER_REF, ...PAGINATION },
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: "twitter_user_mentions",
|
|
172
|
+
path: "/twitter/user/mentions",
|
|
173
|
+
description:
|
|
174
|
+
"Get recent public tweets that mention (@ tag) a user. Searches for tweets directed at the username using the to: operator. Returns matching tweets with author info and metrics. Paginate with cursor. Use this to monitor brand mentions, replies directed at an account, or public conversations about a person.",
|
|
175
|
+
shape: {
|
|
176
|
+
username: z.string().describe(
|
|
177
|
+
"Twitter/X handle WITHOUT the leading @ of the user to find mentions for (e.g. 'openai' to find tweets mentioning @openai).",
|
|
178
|
+
),
|
|
179
|
+
...PAGINATION,
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: "twitter_user_likes",
|
|
184
|
+
path: "/twitter/user/likes",
|
|
185
|
+
description:
|
|
186
|
+
"Get the tweets a user has liked (their public Likes tab), most recent first. Returns each liked tweet with author and metrics, plus a pagination cursor. Use this to infer interests or find content a user has endorsed. Returns empty if the account hides its likes. Requires the numeric user_id (resolve a handle first with twitter_user_info).",
|
|
187
|
+
shape: {
|
|
188
|
+
user_id: z.string().describe(
|
|
189
|
+
"Numeric Twitter/X user id (e.g. '44196397'). Required: this endpoint does not accept a username. Resolve a handle to a user_id first with twitter_user_info.",
|
|
190
|
+
),
|
|
191
|
+
...PAGINATION,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
// ── Reads: followers / following graph ─────────────────────────────────────
|
|
97
195
|
{
|
|
98
196
|
name: "twitter_user_followers",
|
|
99
197
|
path: "/twitter/user/followers",
|
|
@@ -116,24 +214,18 @@ export const TOOLS = [
|
|
|
116
214
|
shape: { ...USER_REF, ...PAGINATION },
|
|
117
215
|
},
|
|
118
216
|
{
|
|
119
|
-
name: "
|
|
120
|
-
path: "/twitter/user/
|
|
217
|
+
name: "twitter_followers_you_know",
|
|
218
|
+
path: "/twitter/user/followers_you_know",
|
|
121
219
|
description:
|
|
122
|
-
"
|
|
123
|
-
shape: { ...USER_REF, ...PAGINATION },
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
name: "twitter_user_mentions",
|
|
127
|
-
path: "/twitter/user/mentions",
|
|
128
|
-
description:
|
|
129
|
-
"Get recent public tweets that mention (@ tag) a user. Searches for tweets directed at the username using the to: operator. Returns matching tweets with author info and metrics. Paginate with cursor. Use this to monitor brand mentions, replies directed at an account, or public conversations about a person.",
|
|
220
|
+
"List the 'Followers you know' for a target user id: the followers of that account that YOUR authenticated account also follows (mutual-connection overlap). Requires an authenticated session behind your key. Returns profile data per overlap account plus a cursor.",
|
|
130
221
|
shape: {
|
|
131
|
-
|
|
132
|
-
"
|
|
222
|
+
user_id: z.string().describe(
|
|
223
|
+
"Numeric user id of the target account to compute shared followers against.",
|
|
133
224
|
),
|
|
134
225
|
...PAGINATION,
|
|
135
226
|
},
|
|
136
227
|
},
|
|
228
|
+
// ── Reads: a single tweet + its conversation ───────────────────────────────
|
|
137
229
|
{
|
|
138
230
|
name: "twitter_tweet_detail",
|
|
139
231
|
path: "/twitter/tweet/detail",
|
|
@@ -174,6 +266,174 @@ export const TOOLS = [
|
|
|
174
266
|
...PAGINATION,
|
|
175
267
|
},
|
|
176
268
|
},
|
|
269
|
+
// ── Reads: authenticated-account surfaces (require a session behind your key) ─
|
|
270
|
+
{
|
|
271
|
+
name: "twitter_home_timeline",
|
|
272
|
+
path: "/twitter/user/home_timeline",
|
|
273
|
+
description:
|
|
274
|
+
"Get YOUR authenticated account's Home timeline (the 'Following'/'For you' feed), most recent first. Requires an authenticated session behind your key. Returns tweets with author and metrics plus a cursor. Use this to read what your account would see when it opens X.",
|
|
275
|
+
shape: { ...PAGINATION },
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: "twitter_bookmarks",
|
|
279
|
+
path: "/twitter/user/bookmarks",
|
|
280
|
+
description:
|
|
281
|
+
"List YOUR authenticated account's bookmarked tweets, most recent first. Requires an authenticated session behind your key. Returns each bookmarked tweet with author and metrics plus a cursor.",
|
|
282
|
+
shape: { ...PAGINATION },
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
name: "twitter_bookmark_search",
|
|
286
|
+
path: "/twitter/user/bookmark_search",
|
|
287
|
+
description:
|
|
288
|
+
"Full-text search within YOUR authenticated account's bookmarks. Requires an authenticated session behind your key. Returns matching bookmarked tweets plus a cursor. Use this to retrieve a previously bookmarked tweet by keyword.",
|
|
289
|
+
shape: {
|
|
290
|
+
query: z.string().describe(
|
|
291
|
+
"Search terms to match against your bookmarked tweets' text.",
|
|
292
|
+
),
|
|
293
|
+
...PAGINATION,
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
name: "twitter_dm_list",
|
|
298
|
+
path: "/twitter/dm/list",
|
|
299
|
+
description:
|
|
300
|
+
"List YOUR authenticated account's Direct Message conversations (inbox), each with the participant and a conversation_id you can pass to twitter_dm_conversation. Requires an authenticated session behind your key. Read-only: this does not send DMs.",
|
|
301
|
+
shape: {},
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
name: "twitter_dm_conversation",
|
|
305
|
+
path: "/twitter/dm/conversation",
|
|
306
|
+
description:
|
|
307
|
+
"Get the messages in one Direct Message conversation by its conversation_id (from twitter_dm_list). Requires an authenticated session behind your key. Returns each message with sender id, time, and text. Read-only: this does not send DMs.",
|
|
308
|
+
shape: {
|
|
309
|
+
conversation_id: z.string().describe(
|
|
310
|
+
"The conversation_id from a twitter_dm_list entry identifying which DM thread to read.",
|
|
311
|
+
),
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
|
|
315
|
+
// ── Writes: tweet authoring ────────────────────────────────────────────────
|
|
316
|
+
{
|
|
317
|
+
name: "twitter_create_tweet",
|
|
318
|
+
path: "/twitter/tweet/create",
|
|
319
|
+
method: "POST",
|
|
320
|
+
write: true,
|
|
321
|
+
description:
|
|
322
|
+
"Post a new tweet AS your authenticated account. Set reply_to to post a reply, or quote to post a quote-tweet. This publishes publicly and is not silently reversible (use twitter_delete_tweet to remove it). Requires an authenticated session with write capability behind your key. Returns the new tweet_id and url.",
|
|
323
|
+
shape: {
|
|
324
|
+
text: z.string().min(1).describe(
|
|
325
|
+
"The tweet body text (1 to 280 characters, or longer if the account has extended limits).",
|
|
326
|
+
),
|
|
327
|
+
reply_to: z.string().optional().describe(
|
|
328
|
+
"Optional. Numeric id of the tweet to reply to. When set, this tweet is posted as a reply in that conversation.",
|
|
329
|
+
),
|
|
330
|
+
quote: z.string().optional().describe(
|
|
331
|
+
"Optional. Numeric id of the tweet to quote. When set, this tweet quote-tweets that tweet.",
|
|
332
|
+
),
|
|
333
|
+
media_ids: z.string().optional().describe(
|
|
334
|
+
"Optional. Comma-separated media id(s) from a prior media upload to attach (images/video).",
|
|
335
|
+
),
|
|
336
|
+
...ACCOUNT,
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
name: "twitter_delete_tweet",
|
|
341
|
+
path: "/twitter/tweet/delete",
|
|
342
|
+
method: "POST",
|
|
343
|
+
write: true,
|
|
344
|
+
destructive: true,
|
|
345
|
+
description:
|
|
346
|
+
"Delete a tweet AS your authenticated account. Irreversible: the tweet is permanently removed. You can only delete tweets your authenticated account authored. Provide the tweet id or url. Requires write capability behind your key.",
|
|
347
|
+
shape: { ...TWEET_REF, ...ACCOUNT },
|
|
348
|
+
},
|
|
349
|
+
// ── Writes: engagement (favorite / retweet / bookmark) + inverses ──────────
|
|
350
|
+
{
|
|
351
|
+
name: "twitter_favorite_tweet",
|
|
352
|
+
path: "/twitter/tweet/favorite",
|
|
353
|
+
method: "POST",
|
|
354
|
+
write: true,
|
|
355
|
+
description:
|
|
356
|
+
"Like (favorite) a tweet AS your authenticated account. Provide the tweet id or url. Requires write capability behind your key. Reverse with twitter_unfavorite_tweet.",
|
|
357
|
+
shape: { ...TWEET_REF, ...ACCOUNT },
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
name: "twitter_unfavorite_tweet",
|
|
361
|
+
path: "/twitter/tweet/unfavorite",
|
|
362
|
+
method: "POST",
|
|
363
|
+
write: true,
|
|
364
|
+
destructive: true,
|
|
365
|
+
description:
|
|
366
|
+
"Remove a like (unfavorite) from a tweet AS your authenticated account. Provide the tweet id or url. Requires write capability behind your key.",
|
|
367
|
+
shape: { ...TWEET_REF, ...ACCOUNT },
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
name: "twitter_retweet",
|
|
371
|
+
path: "/twitter/tweet/retweet",
|
|
372
|
+
method: "POST",
|
|
373
|
+
write: true,
|
|
374
|
+
description:
|
|
375
|
+
"Retweet a tweet AS your authenticated account. Provide the tweet id or url. Requires write capability behind your key. Reverse with twitter_unretweet.",
|
|
376
|
+
shape: { ...TWEET_REF, ...ACCOUNT },
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
name: "twitter_unretweet",
|
|
380
|
+
path: "/twitter/tweet/unretweet",
|
|
381
|
+
method: "POST",
|
|
382
|
+
write: true,
|
|
383
|
+
destructive: true,
|
|
384
|
+
description:
|
|
385
|
+
"Undo a retweet AS your authenticated account. Provide the tweet id or url. Requires write capability behind your key.",
|
|
386
|
+
shape: { ...TWEET_REF, ...ACCOUNT },
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
name: "twitter_bookmark_tweet",
|
|
390
|
+
path: "/twitter/tweet/bookmark",
|
|
391
|
+
method: "POST",
|
|
392
|
+
write: true,
|
|
393
|
+
description:
|
|
394
|
+
"Bookmark a tweet to YOUR authenticated account's private bookmarks. Provide the tweet id or url. Requires write capability behind your key. Reverse with twitter_unbookmark_tweet.",
|
|
395
|
+
shape: { ...TWEET_REF, ...ACCOUNT },
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
name: "twitter_unbookmark_tweet",
|
|
399
|
+
path: "/twitter/tweet/unbookmark",
|
|
400
|
+
method: "POST",
|
|
401
|
+
write: true,
|
|
402
|
+
destructive: true,
|
|
403
|
+
description:
|
|
404
|
+
"Remove a tweet from YOUR authenticated account's bookmarks. Provide the tweet id or url. Requires write capability behind your key.",
|
|
405
|
+
shape: { ...TWEET_REF, ...ACCOUNT },
|
|
406
|
+
},
|
|
407
|
+
// ── Writes: follow graph ───────────────────────────────────────────────────
|
|
408
|
+
{
|
|
409
|
+
name: "twitter_follow_user",
|
|
410
|
+
path: "/twitter/user/follow",
|
|
411
|
+
method: "POST",
|
|
412
|
+
write: true,
|
|
413
|
+
description:
|
|
414
|
+
"Follow a user AS your authenticated account, by numeric user_id. Requires write capability behind your key. Reverse with twitter_unfollow_user.",
|
|
415
|
+
shape: {
|
|
416
|
+
user_id: z.string().describe(
|
|
417
|
+
"Numeric user id of the account to follow. Resolve a handle to a user_id first with twitter_user_info.",
|
|
418
|
+
),
|
|
419
|
+
...ACCOUNT,
|
|
420
|
+
},
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
name: "twitter_unfollow_user",
|
|
424
|
+
path: "/twitter/user/unfollow",
|
|
425
|
+
method: "POST",
|
|
426
|
+
write: true,
|
|
427
|
+
destructive: true,
|
|
428
|
+
description:
|
|
429
|
+
"Unfollow a user AS your authenticated account, by numeric user_id. Requires write capability behind your key.",
|
|
430
|
+
shape: {
|
|
431
|
+
user_id: z.string().describe(
|
|
432
|
+
"Numeric user id of the account to unfollow.",
|
|
433
|
+
),
|
|
434
|
+
...ACCOUNT,
|
|
435
|
+
},
|
|
436
|
+
},
|
|
177
437
|
];
|
|
178
438
|
|
|
179
439
|
// Pure query-string builder: drops undefined/null/empty values, URL-encodes the rest.
|