@twitterapis/mcp 0.1.0 → 0.1.1

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 ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ ## 0.1.1 (2026-06-24)
4
+
5
+ ### Improvements
6
+
7
+ - Tool descriptions rewritten. All 16 tool descriptions and parameter hints now use precise, concrete language matched to how MCP clients surface them. Removed hedging phrases, tightened scope statements, and added concrete value hints for paginated parameters (cursor, count limits).
8
+ - Error hints added. Each tool now carries structured error guidance covering the five most common failure codes (401, 402, 403, 404, 429) with a plain-English fix per code, so agents can self-correct without a docs lookup.
9
+ - README optimized. Quick-start, setup matrix (Claude Desktop, Cursor, Windsurf, VS Code), configuration table, full tool reference, usage examples, troubleshooting section, and pricing note all revised for clarity and scannability.
10
+ - GitHub repository established. The package now carries a canonical repository field pointing to github.com/TwitterAPIs/twitterapis-mcp (public, MIT licensed).
11
+
12
+ ### No breaking changes
13
+
14
+ All 16 tool names, parameter names, and API endpoint mappings are unchanged. Existing `npx @twitterapis/mcp@latest` invocations update automatically.
15
+
16
+ ## 0.1.0
17
+
18
+ First public release of the `@twitterapis/mcp` npm package. 16 read-only Twitter/X tools: search, user info, timeline, followers and following, verified followers, media, mentions, tweet detail, replies, threads, retweeters, and list members.
package/README.md CHANGED
@@ -1,16 +1,18 @@
1
1
  # @twitterapis/mcp
2
2
 
3
- Official **Model Context Protocol** server for [twitterapis.com](https://www.twitterapis.com) the Twitter / X **read** API as native tools for Claude, Cursor, and any MCP client.
3
+ Official **Model Context Protocol** server for [twitterapis.com](https://www.twitterapis.com), the Twitter / X **read** API as native tools for Claude, Cursor, Windsurf, and any MCP client.
4
4
 
5
- Ask your agent to *"find the latest tweets about AI agents"* or *"pull @openai's followers"* 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 per call.
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
 
7
- ## Install
7
+ ## Quick start
8
8
 
9
- No install needed run it on demand with `npx`. You only need an API key (free `$0.50` in credits, no card): **https://www.twitterapis.com/signup**.
9
+ No install needed. Run with `npx`. You need one thing: an API key (free $0.50 in credits, no card required): **[twitterapis.com/signup](https://www.twitterapis.com/signup)**.
10
+
11
+ ## Setup
10
12
 
11
13
  ### Claude Desktop
12
14
 
13
- Add to `claude_desktop_config.json` (Settings → Developer → Edit Config):
15
+ Edit `claude_desktop_config.json` (Settings → Developer → Edit Config):
14
16
 
15
17
  ```json
16
18
  {
@@ -24,9 +26,27 @@ Add to `claude_desktop_config.json` (Settings → Developer → Edit Config):
24
26
  }
25
27
  ```
26
28
 
29
+ Restart Claude Desktop. The `twitter_*` tools appear in the tool picker.
30
+
27
31
  ### Cursor
28
32
 
29
- `~/.cursor/mcp.json` (or Settings → MCP → Add):
33
+ `~/.cursor/mcp.json` (or Settings → MCP → Add New Server):
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "twitterapis": {
39
+ "command": "npx",
40
+ "args": ["-y", "@twitterapis/mcp@latest"],
41
+ "env": { "TWITTERAPIS_KEY": "YOUR_API_KEY" }
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ ### Windsurf
48
+
49
+ `~/.codeium/windsurf/mcp_config.json`:
30
50
 
31
51
  ```json
32
52
  {
@@ -40,48 +60,129 @@ Add to `claude_desktop_config.json` (Settings → Developer → Edit Config):
40
60
  }
41
61
  ```
42
62
 
43
- Restart the client and the `twitter_*` tools appear.
63
+ ### VS Code (Copilot / agent mode)
64
+
65
+ `.vscode/mcp.json` in your workspace, or the user-level MCP settings:
66
+
67
+ ```json
68
+ {
69
+ "servers": {
70
+ "twitterapis": {
71
+ "type": "stdio",
72
+ "command": "npx",
73
+ "args": ["-y", "@twitterapis/mcp@latest"],
74
+ "env": { "TWITTERAPIS_KEY": "YOUR_API_KEY" }
75
+ }
76
+ }
77
+ }
78
+ ```
44
79
 
45
80
  ## Configuration
46
81
 
47
82
  | Env var | Required | Default | Purpose |
48
83
  |---|---|---|---|
49
- | `TWITTERAPIS_KEY` | | | Your API key from the dashboard |
50
- | `TWITTERAPIS_BASE_URL` | | `https://api.twitterapis.com` | Override the API host |
51
- | `TWITTERAPIS_TIMEOUT_MS` | | `30000` | Per-request timeout |
84
+ | `TWITTERAPIS_KEY` | Yes | (none) | API key from [dashboard](https://www.twitterapis.com/dashboard) |
85
+ | `TWITTERAPIS_BASE_URL` | No | `https://api.twitterapis.com` | Override the API host |
86
+ | `TWITTERAPIS_TIMEOUT_MS` | No | `30000` | Per-request timeout in milliseconds |
52
87
 
53
88
  ## Tools
54
89
 
55
- All read-only. User endpoints take `username` **or** `user_id`; tweet endpoints take `id` **or** `url`; list endpoints page with `count` + `cursor`.
90
+ All 16 tools are read-only. User endpoints accept `username` (handle without @) **or** `user_id`; tweet endpoints accept `id` **or** `url`; paginated endpoints return a `cursor` you pass back to get the next page.
56
91
 
57
92
  | Tool | What it does |
58
93
  |---|---|
59
- | `twitter_advanced_search` | Search tweets with X operators (`from:`, `min_faves:`, `filter:`, ) |
60
- | `twitter_user_search` | Search accounts by name/keyword |
61
- | `twitter_user_info` | Full profile by handle |
62
- | `twitter_user_info_by_id` | Full profile by numeric id |
63
- | `twitter_user_tweets` | A user's recent tweets (no replies) |
94
+ | `twitter_advanced_search` | Search tweets with X operators (`from:`, `min_faves:`, `since:`, `filter:links`, etc.) |
95
+ | `twitter_user_search` | Find user accounts by name or keyword |
96
+ | `twitter_user_info` | Full profile by handle (bio, counts, verification, location) |
97
+ | `twitter_user_info_by_id` | Full profile by numeric user id |
98
+ | `twitter_user_tweets` | A user's recent original tweets (replies excluded) |
64
99
  | `twitter_user_tweets_and_replies` | A user's full timeline (tweets + replies) |
65
100
  | `twitter_user_followers` | Accounts that follow a user |
66
101
  | `twitter_user_following` | Accounts a user follows |
67
- | `twitter_user_verified_followers` | A user's verified followers |
68
- | `twitter_user_media` | Media a user has posted |
69
- | `twitter_user_mentions` | Recent tweets mentioning a user |
70
- | `twitter_tweet_detail` | One tweet's full detail |
102
+ | `twitter_user_verified_followers` | A user's verified followers only |
103
+ | `twitter_user_media` | Images and videos a user has posted |
104
+ | `twitter_user_mentions` | Recent public tweets mentioning a user |
105
+ | `twitter_tweet_detail` | Single tweet: text, author, metrics, media, quoted/reply context |
71
106
  | `twitter_tweet_replies` | Replies to a tweet |
72
- | `twitter_tweet_thread` | A tweet's self-thread |
107
+ | `twitter_tweet_thread` | Full author thread (connected tweet chain by same author) |
73
108
  | `twitter_tweet_retweeters` | Accounts that retweeted a tweet |
74
- | `twitter_list_members` | Members of a List |
109
+ | `twitter_list_members` | Members of a Twitter/X List |
110
+
111
+ ## Usage examples
112
+
113
+ ### Search for trending AI tweets
114
+
115
+ > "Find the most popular tweets about AI agents posted this week"
116
+
117
+ The agent calls `twitter_advanced_search` with:
118
+ ```
119
+ query: "AI agents min_faves:200 since:2024-01-01"
120
+ product: "Top"
121
+ count: 20
122
+ ```
123
+
124
+ ### Pull a user's recent posts
125
+
126
+ > "Get the last 10 tweets from @sama"
127
+
128
+ The agent calls `twitter_user_tweets` with:
129
+ ```
130
+ username: "sama"
131
+ count: 10
132
+ ```
133
+
134
+ ### Read a full thread
135
+
136
+ > "Get the full thread for this tweet: https://x.com/karpathy/status/1849....."
137
+
138
+ The agent calls `twitter_tweet_thread` with:
139
+ ```
140
+ url: "https://x.com/karpathy/status/1849....."
141
+ ```
142
+
143
+ ### Paginate through followers
144
+
145
+ > "List the first 100 followers of @openai, then the next 100"
146
+
147
+ First call, `twitter_user_followers`: `{ username: "openai", count: 100 }`
148
+ Second call, pass back the `cursor` from the first response: `{ username: "openai", count: 100, cursor: "<cursor from response>" }`
149
+
150
+ ### Monitor brand mentions
151
+
152
+ > "Show me recent tweets mentioning @twitterapis"
153
+
154
+ The agent calls `twitter_user_mentions` with:
155
+ ```
156
+ username: "twitterapis"
157
+ count: 50
158
+ ```
159
+
160
+ ## Troubleshooting
161
+
162
+ **`HTTP 401 (invalid or missing API key)`** Check that `TWITTERAPIS_KEY` is set correctly in your MCP client config and matches the key shown in your [dashboard](https://www.twitterapis.com/dashboard).
163
+
164
+ **`HTTP 402 (insufficient credits)`** Top up at [twitterapis.com/dashboard](https://www.twitterapis.com/dashboard). Your first $0.50 is free at signup.
165
+
166
+ **`HTTP 403 (access forbidden)`** The account or tweet may be private/protected, or your plan does not include this endpoint.
167
+
168
+ **`HTTP 404 (not found)`** The user, tweet, or list may have been deleted, suspended, or the id/handle is wrong.
169
+
170
+ **`HTTP 429 (rate limited)`** Wait a few seconds and retry. If you hit this frequently, add `"TWITTERAPIS_TIMEOUT_MS": "60000"` to your env config and space out bulk requests.
171
+
172
+ **`Request failed: timed out after 30000ms`** The default timeout is 30 s. For large paginated fetches set `TWITTERAPIS_TIMEOUT_MS` to a higher value (e.g. `60000`).
173
+
174
+ **Tools do not appear in Claude / Cursor** Ensure `npx` is on your PATH and Node.js 18+ is installed (`node --version`). Check MCP client logs for startup errors.
75
175
 
76
176
  ## Pricing
77
177
 
78
- Calls are billed to your twitterapis.com account at the standard read rate (`$0.0008`/call); your first `$0.50` is free. See [pricing](https://www.twitterapis.com/pricing).
178
+ Calls are billed to your twitterapis.com account at the standard read rate ($0.0008/call, or $0.04 per 1,000 tweets (each call returns about 20 tweets)); your first $0.50 is free. See [twitterapis.com/pricing](https://www.twitterapis.com/pricing).
79
179
 
80
180
  ## Links
81
181
 
82
- - Docs https://docs.twitterapis.com
83
- - Dashboard / keys https://www.twitterapis.com/dashboard
84
- - REST API (no MCP needed) https://api.twitterapis.com
182
+ - Docs: [docs.twitterapis.com](https://docs.twitterapis.com)
183
+ - Dashboard / API keys: [twitterapis.com/dashboard](https://www.twitterapis.com/dashboard)
184
+ - REST API (without MCP): [api.twitterapis.com](https://api.twitterapis.com)
185
+ - Status: [twitterapis.com/status](https://www.twitterapis.com/status)
85
186
 
86
187
  ## License
87
188
 
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@twitterapis/mcp",
3
- "version": "0.1.0",
4
- "description": "Official MCP server for twitterapis.com the Twitter/X read API (search, users, followers, tweets, threads, lists) as native tools for Claude, Cursor, and any MCP client.",
3
+ "version": "0.1.1",
4
+ "description": "Official MCP server for twitterapis.com, the Twitter/X read API (search, users, followers, tweets, threads, lists) as native tools for Claude, Cursor, and any MCP client.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/TwitterAPIs/twitterapis-mcp.git"
8
+ },
5
9
  "type": "module",
6
10
  "bin": {
7
11
  "twitterapis-mcp": "src/index.js"
@@ -10,7 +14,8 @@
10
14
  "files": [
11
15
  "src",
12
16
  "README.md",
13
- "LICENSE"
17
+ "LICENSE",
18
+ "CHANGELOG.md"
14
19
  ],
15
20
  "engines": {
16
21
  "node": ">=18"
package/src/index.js CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
- // @twitterapis/mcp official MCP server for twitterapis.com
2
+ // @twitterapis/mcp, official MCP server for twitterapis.com
3
3
  //
4
4
  // Exposes the Twitter / X READ API as native MCP tools (search, users,
5
5
  // followers/following, tweets, threads, lists, mentions) for Claude, Cursor,
6
6
  // and any MCP client. Each tool is a thin, typed wrapper over a REST endpoint
7
- // at https://api.twitterapis.com the server holds no state and forwards your
7
+ // at https://api.twitterapis.com. The server holds no state and forwards your
8
8
  // API key on every call. The tool catalog lives in ./tools.js.
9
9
  //
10
10
  // Config (env):
11
- // TWITTERAPIS_KEY required your key from https://www.twitterapis.com/signup
12
- // TWITTERAPIS_BASE_URL optional defaults to https://api.twitterapis.com
13
- // TWITTERAPIS_TIMEOUT_MS optional — per-request timeout (default 30000)
11
+ // TWITTERAPIS_KEY required. Your key from https://www.twitterapis.com/signup
12
+ // TWITTERAPIS_BASE_URL optional. Defaults to https://api.twitterapis.com
13
+ // TWITTERAPIS_TIMEOUT_MS optional. Per-request timeout (default 30000)
14
14
  //
15
15
  // Run: npx -y @twitterapis/mcp@latest (stdio transport)
16
16
 
@@ -46,7 +46,7 @@ async function callEndpoint(path, args) {
46
46
  Authorization: `Bearer ${API_KEY}`,
47
47
  "x-api-key": API_KEY,
48
48
  accept: "application/json",
49
- "user-agent": "twitterapis-mcp/0.1.0",
49
+ "user-agent": "twitterapis-mcp/0.1.1",
50
50
  },
51
51
  signal: ctrl.signal,
52
52
  });
@@ -54,12 +54,18 @@ async function callEndpoint(path, args) {
54
54
  if (!res.ok) {
55
55
  const hint =
56
56
  res.status === 401
57
- ? " (check TWITTERAPIS_KEY)"
57
+ ? " (invalid or missing API key, verify TWITTERAPIS_KEY at https://www.twitterapis.com/dashboard)"
58
58
  : res.status === 402
59
- ? " (insufficient credits top up at https://www.twitterapis.com/dashboard)"
60
- : res.status === 429
61
- ? " (rate limited retry shortly)"
62
- : "";
59
+ ? " (insufficient credits, top up at https://www.twitterapis.com/dashboard)"
60
+ : res.status === 403
61
+ ? " (access forbidden. The resource may be private or your plan does not include this endpoint)"
62
+ : res.status === 404
63
+ ? " (not found. The user, tweet, or list may have been deleted or the id is wrong)"
64
+ : res.status === 429
65
+ ? " (rate limited. Wait a few seconds and retry; reduce request frequency or increase TWITTERAPIS_TIMEOUT_MS if needed)"
66
+ : res.status >= 500
67
+ ? " (upstream API error. Retry in a moment; if persistent, check https://www.twitterapis.com/status)"
68
+ : "";
63
69
  return { isError: true, content: [{ type: "text", text: `HTTP ${res.status}${hint}: ${body.slice(0, 1200)}` }] };
64
70
  }
65
71
  return { content: [{ type: "text", text: body }] };
@@ -72,7 +78,7 @@ async function callEndpoint(path, args) {
72
78
  }
73
79
 
74
80
  // ── MCP server ───────────────────────────────────────────────────────────────
75
- const server = new McpServer({ name: "twitterapis", version: "0.1.0" });
81
+ const server = new McpServer({ name: "twitterapis", version: "0.1.1" });
76
82
 
77
83
  for (const tool of TOOLS) {
78
84
  server.registerTool(
package/src/tools.js CHANGED
@@ -5,68 +5,175 @@ import { z } from "zod";
5
5
 
6
6
  // ── Shared Zod input-schema fragments ───────────────────────────────────────
7
7
  const PAGINATION = {
8
- count: z.number().int().positive().optional().describe("Max items to return for this page (endpoint default applies if omitted)."),
9
- cursor: z.string().optional().describe("Pagination cursor returned by a previous call to fetch the next page."),
8
+ count: z.number().int().min(1).max(200).optional().describe(
9
+ "Max items to return for this page. Typical range 1 to 200; endpoint default (20) applies if omitted. To page through results, pass the cursor from the previous response.",
10
+ ),
11
+ cursor: z.string().optional().describe(
12
+ "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.",
13
+ ),
10
14
  };
11
15
  const USER_REF = {
12
- username: z.string().optional().describe('Twitter/X handle, without the leading @ (e.g. "elonmusk"). Provide this OR user_id.'),
13
- user_id: z.string().optional().describe("Numeric user id. Provide this OR username."),
16
+ username: z.string().optional().describe(
17
+ 'Twitter/X handle WITHOUT the leading @ (e.g. "elonmusk", "openai"). Provide exactly one of username or user_id.',
18
+ ),
19
+ user_id: z.string().optional().describe(
20
+ 'Numeric Twitter/X user id (e.g. "44196397"). Provide exactly one of username or user_id.',
21
+ ),
14
22
  };
15
23
  const TWEET_REF = {
16
- id: z.string().optional().describe('Tweet id (e.g. "1789..."). Provide this OR url.'),
17
- url: z.string().optional().describe("Full tweet URL (https://x.com/<user>/status/<id>). Provide this OR id."),
24
+ id: z.string().optional().describe(
25
+ 'Tweet/post numeric id (e.g. "1789012345678901234"). Provide exactly one of id or url.',
26
+ ),
27
+ url: z.string().optional().describe(
28
+ 'Full tweet URL, e.g. "https://x.com/elonmusk/status/1789012345678901234". Provide exactly one of id or url.',
29
+ ),
18
30
  };
19
31
 
20
32
  // ── Read-only tool catalog. Tool arg names map 1:1 to endpoint query params. ─
21
33
  export const TOOLS = [
22
- { name: "twitter_advanced_search", path: "/twitter/tweet/advanced_search",
23
- description: "Search recent tweets with X's advanced-search syntax (operators like from:, to:, since:, until:, min_faves:, filter:). Returns matching tweets with author, metrics, and a cursor for paging.",
24
- shape: { query: z.string().describe('Search query, e.g. "AI agents min_faves:100" or "from:openai".'), product: z.enum(["Top", "Latest", "Media", "People"]).optional().describe('Result tab. "Latest" for reverse-chron, "Top" for ranked (default).'), ...PAGINATION } },
25
- { name: "twitter_user_search", path: "/twitter/user/search",
26
- description: "Search for users/accounts by name or keyword. Returns matching profiles with a paging cursor.",
27
- shape: { query: z.string().describe("Name or keyword to search accounts for."), ...PAGINATION } },
28
- { name: "twitter_user_info", path: "/twitter/user/info",
29
- description: "Get a user's full profile by handle: bio, follower/following counts, verification, location, created date, pinned tweet.",
30
- shape: { username: z.string().describe("Twitter/X handle without the leading @.") } },
31
- { name: "twitter_user_info_by_id", path: "/twitter/user/info_by_id",
32
- description: "Get a user's full profile by numeric user id (use when you have the id but not the handle).",
33
- shape: { user_id: z.string().describe("Numeric user id.") } },
34
- { name: "twitter_user_tweets", path: "/twitter/user/tweets",
35
- description: "Get a user's recent original tweets (no replies). Cursored.",
36
- shape: { ...USER_REF, ...PAGINATION } },
37
- { name: "twitter_user_tweets_and_replies", path: "/twitter/user/tweets_and_replies",
38
- description: "Get a user's recent tweets AND replies (their full timeline). Cursored.",
39
- shape: { ...USER_REF, ...PAGINATION } },
40
- { name: "twitter_user_followers", path: "/twitter/user/followers",
41
- description: "List the accounts that follow a user. Cursored.",
42
- shape: { ...USER_REF, ...PAGINATION } },
43
- { name: "twitter_user_following", path: "/twitter/user/following",
44
- description: "List the accounts a user follows. Cursored.",
45
- shape: { ...USER_REF, ...PAGINATION } },
46
- { name: "twitter_user_verified_followers", path: "/twitter/user/verified_followers",
47
- description: "List a user's verified (blue/business) followers. Cursored.",
48
- shape: { ...USER_REF, ...PAGINATION } },
49
- { name: "twitter_user_media", path: "/twitter/user/media",
50
- description: "Get the media (images/videos) a user has posted. Cursored.",
51
- shape: { ...USER_REF, ...PAGINATION } },
52
- { name: "twitter_user_mentions", path: "/twitter/user/mentions",
53
- description: "Get recent tweets that mention a user (implemented as a to:<username> search). Cursored.",
54
- shape: { username: z.string().describe("Twitter/X handle without the leading @."), ...PAGINATION } },
55
- { name: "twitter_tweet_detail", path: "/twitter/tweet/detail",
56
- description: "Get a single tweet's full detail: text, author, metrics, media, and quoted/replied context.",
57
- shape: { ...TWEET_REF } },
58
- { name: "twitter_tweet_replies", path: "/twitter/tweet/replies",
59
- description: "Get the replies to a tweet. Cursored.",
60
- shape: { ...TWEET_REF, ...PAGINATION } },
61
- { name: "twitter_tweet_thread", path: "/twitter/tweet/thread",
62
- description: "Get the full self-thread for a tweet (the author's connected chain). Cursored.",
63
- shape: { ...TWEET_REF, ...PAGINATION } },
64
- { name: "twitter_tweet_retweeters", path: "/twitter/tweet/retweeters",
65
- description: "List the accounts that retweeted a tweet. Cursored.",
66
- shape: { ...TWEET_REF, ...PAGINATION } },
67
- { name: "twitter_list_members", path: "/twitter/list/members",
68
- description: "List the members of a Twitter/X List by list id. Cursored.",
69
- shape: { list_id: z.string().describe("Numeric List id."), ...PAGINATION } },
34
+ {
35
+ name: "twitter_advanced_search",
36
+ path: "/twitter/tweet/advanced_search",
37
+ description:
38
+ "Search recent tweets using X's advanced-search operators. Supports from:, to:, since:YYYY-MM-DD, until:YYYY-MM-DD, min_faves:N, min_retweets:N, filter:links, -filter:replies, lang:en, and free-text. Returns tweet text, author info, engagement metrics, and a pagination cursor. Use product='Latest' for chronological results; 'Top' (default) for engagement-ranked. Example queries: 'AI agents min_faves:100', 'from:openai filter:links since:2024-01-01', '#buildinpublic -filter:replies lang:en'.",
39
+ shape: {
40
+ query: z.string().describe(
41
+ "Full advanced-search query string. Supports X operators: from:handle, to:handle, since:YYYY-MM-DD, until:YYYY-MM-DD, min_faves:N, min_retweets:N, filter:links, filter:images, filter:videos, -filter:replies, lang:en, #hashtag, \"exact phrase\". Example: 'from:openai min_faves:500 since:2024-01-01'.",
42
+ ),
43
+ product: z.enum(["Top", "Latest", "Media", "People"]).optional().describe(
44
+ "Result ranking mode. 'Latest' = reverse-chronological (best for monitoring). 'Top' = engagement-ranked (best for finding popular tweets, default when omitted). 'Media' = tweets with images/video. 'People' = matching user accounts.",
45
+ ),
46
+ ...PAGINATION,
47
+ },
48
+ },
49
+ {
50
+ name: "twitter_user_search",
51
+ path: "/twitter/user/search",
52
+ description:
53
+ "Search for Twitter/X user accounts by name, keyword, or topic. Returns matching profiles (username, display name, bio, follower count, verification status) with a pagination cursor. Use this to discover accounts in a niche, find brand handles, or locate a person when you only know their name.",
54
+ shape: {
55
+ query: z.string().describe(
56
+ "Name, keyword, or topic to search accounts for. Examples: 'OpenAI', 'AI researcher', 'tech founder'.",
57
+ ),
58
+ ...PAGINATION,
59
+ },
60
+ },
61
+ {
62
+ name: "twitter_user_info",
63
+ path: "/twitter/user/info",
64
+ description:
65
+ "Get a user's complete public profile by their @handle: display name, bio, follower count, following count, verification status, location, website, account creation date, and pinned tweet. Use this before fetching tweets or followers to confirm the account exists and resolve the numeric user_id.",
66
+ shape: {
67
+ username: z.string().describe(
68
+ "Twitter/X handle WITHOUT the leading @ (e.g. 'elonmusk', 'openai', 'sama').",
69
+ ),
70
+ },
71
+ },
72
+ {
73
+ name: "twitter_user_info_by_id",
74
+ path: "/twitter/user/info_by_id",
75
+ description:
76
+ "Get a user's complete public profile by their numeric user id. Identical response to twitter_user_info. Use this when you already have a user_id from a previous API response and want to avoid a handle lookup.",
77
+ shape: {
78
+ user_id: z.string().describe(
79
+ "Numeric Twitter/X user id (e.g. '44196397' for @elonmusk). Found in responses from other tools as user_id or author_id.",
80
+ ),
81
+ },
82
+ },
83
+ {
84
+ name: "twitter_user_tweets",
85
+ path: "/twitter/user/tweets",
86
+ 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.",
88
+ shape: { ...USER_REF, ...PAGINATION },
89
+ },
90
+ {
91
+ name: "twitter_user_tweets_and_replies",
92
+ path: "/twitter/user/tweets_and_replies",
93
+ description:
94
+ "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
+ shape: { ...USER_REF, ...PAGINATION },
96
+ },
97
+ {
98
+ name: "twitter_user_followers",
99
+ path: "/twitter/user/followers",
100
+ description:
101
+ "List the accounts that follow a given user. Returns profile data for each follower (username, display name, bio, follower count). Paginate with cursor for large audiences. Useful for audience analysis, finding who follows a brand or influencer.",
102
+ shape: { ...USER_REF, ...PAGINATION },
103
+ },
104
+ {
105
+ name: "twitter_user_following",
106
+ path: "/twitter/user/following",
107
+ description:
108
+ "List the accounts that a given user follows. Returns profile data for each account followed. Paginate with cursor. Useful for mapping a user's information sources, influencer networks, or competitor monitoring lists.",
109
+ shape: { ...USER_REF, ...PAGINATION },
110
+ },
111
+ {
112
+ name: "twitter_user_verified_followers",
113
+ path: "/twitter/user/verified_followers",
114
+ description:
115
+ "List a user's followers who have a verified account (checkmark). Filters the follower list to verified accounts only, useful for identifying notable or institutional followers. Paginate with cursor.",
116
+ shape: { ...USER_REF, ...PAGINATION },
117
+ },
118
+ {
119
+ name: "twitter_user_media",
120
+ path: "/twitter/user/media",
121
+ description:
122
+ "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.",
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.",
130
+ shape: {
131
+ username: z.string().describe(
132
+ "Twitter/X handle WITHOUT the leading @ of the user to find mentions for (e.g. 'openai' to find tweets mentioning @openai).",
133
+ ),
134
+ ...PAGINATION,
135
+ },
136
+ },
137
+ {
138
+ name: "twitter_tweet_detail",
139
+ path: "/twitter/tweet/detail",
140
+ description:
141
+ "Get the full detail of a single tweet: text, author profile, post timestamp, like/retweet/reply/quote counts, attached media, referenced quoted tweet, and parent reply context. Use this to inspect a specific tweet before fetching its replies or thread. Accepts either the tweet id or its full URL.",
142
+ shape: { ...TWEET_REF },
143
+ },
144
+ {
145
+ name: "twitter_tweet_replies",
146
+ path: "/twitter/tweet/replies",
147
+ description:
148
+ "Get replies to a specific tweet. Returns each reply tweet with author, text, and metrics. Paginate with cursor to load more. Use this to read the conversation under a tweet, gauge sentiment, or find notable responses.",
149
+ shape: { ...TWEET_REF, ...PAGINATION },
150
+ },
151
+ {
152
+ name: "twitter_tweet_thread",
153
+ path: "/twitter/tweet/thread",
154
+ description:
155
+ "Get all tweets in a thread: the connected chain of tweets posted by the SAME author in sequence (a tweetstorm or numbered thread). Pass any tweet id/url from the thread and the API returns the full ordered sequence. Paginate with cursor for long threads. Does NOT return replies from other users, use twitter_tweet_replies for that.",
156
+ shape: { ...TWEET_REF, ...PAGINATION },
157
+ },
158
+ {
159
+ name: "twitter_tweet_retweeters",
160
+ path: "/twitter/tweet/retweeters",
161
+ description:
162
+ "List the accounts that retweeted a specific tweet. Returns profile data for each retweeter. Paginate with cursor. Useful for finding who amplified a piece of content or mapping a tweet's distribution network.",
163
+ shape: { ...TWEET_REF, ...PAGINATION },
164
+ },
165
+ {
166
+ name: "twitter_list_members",
167
+ path: "/twitter/list/members",
168
+ description:
169
+ "List the members of a Twitter/X List by its numeric list id. Returns profile data for each member. Paginate with cursor. Use this to enumerate curated account sets, including competitor lists, industry watchlists, or media outlet lists. The list_id appears in the X.com list URL (x.com/i/lists/<list_id>).",
170
+ shape: {
171
+ list_id: z.string().describe(
172
+ "Numeric Twitter/X List id. Found in the list URL: x.com/i/lists/<list_id>.",
173
+ ),
174
+ ...PAGINATION,
175
+ },
176
+ },
70
177
  ];
71
178
 
72
179
  // Pure query-string builder: drops undefined/null/empty values, URL-encodes the rest.