x-mcp-server 1.4.0__tar.gz

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.
@@ -0,0 +1,59 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+
7
+ permissions:
8
+ contents: write
9
+
10
+ jobs:
11
+ release:
12
+ runs-on: ubuntu-latest
13
+ environment: pypi
14
+ permissions:
15
+ contents: write
16
+ id-token: write
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ with:
20
+ fetch-depth: 0
21
+
22
+ - name: Get version from pyproject.toml
23
+ id: version
24
+ run: |
25
+ VERSION=$(grep -m1 'version' pyproject.toml | sed 's/.*"\(.*\)".*/\1/')
26
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
27
+ echo "tag=v$VERSION" >> "$GITHUB_OUTPUT"
28
+
29
+ - name: Check if tag exists
30
+ id: check
31
+ run: |
32
+ if git rev-parse "v${{ steps.version.outputs.version }}" >/dev/null 2>&1; then
33
+ echo "exists=true" >> "$GITHUB_OUTPUT"
34
+ else
35
+ echo "exists=false" >> "$GITHUB_OUTPUT"
36
+ fi
37
+
38
+ - name: Install uv
39
+ if: steps.check.outputs.exists == 'false'
40
+ uses: astral-sh/setup-uv@v4
41
+
42
+ - name: Build package
43
+ if: steps.check.outputs.exists == 'false'
44
+ run: uv build --out-dir dist
45
+
46
+ - name: Create GitHub Release
47
+ if: steps.check.outputs.exists == 'false'
48
+ uses: softprops/action-gh-release@v2
49
+ with:
50
+ tag_name: ${{ steps.version.outputs.tag }}
51
+ name: ${{ steps.version.outputs.tag }}
52
+ generate_release_notes: true
53
+ files: dist/*
54
+
55
+ - name: Publish to PyPI
56
+ if: steps.check.outputs.exists == 'false'
57
+ run: uv publish dist/*
58
+ env:
59
+ UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
@@ -0,0 +1,9 @@
1
+ *.py[oc]
2
+ __pycache__/
3
+ build/
4
+ dist/
5
+ wheels/
6
+ *.egg-info
7
+ .venv
8
+ .env
9
+ token.json
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 MindMade
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,318 @@
1
+ Metadata-Version: 2.4
2
+ Name: x-mcp-server
3
+ Version: 1.4.0
4
+ Summary: MCP server for X (Twitter) API — post, search, like, retweet, follow, and read tweets
5
+ Project-URL: Homepage, https://github.com/MindMadeLab/x-mcp
6
+ Project-URL: Repository, https://github.com/MindMadeLab/x-mcp
7
+ Project-URL: Issues, https://github.com/MindMadeLab/x-mcp/issues
8
+ Author-email: MindMade <info@mindmade.ai>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Requires-Python: >=3.11
12
+ Requires-Dist: mcp[cli]>=1.8.0
13
+ Requires-Dist: python-dotenv>=1.0.0
14
+ Requires-Dist: tweepy>=4.14.0
15
+ Description-Content-Type: text/markdown
16
+
17
+ <div align="center">
18
+ <b>x-mcp-server</b>
19
+
20
+ <p align="center">
21
+ <i>Your AI Assistant's Gateway to X (Twitter)!</i>
22
+ </p>
23
+
24
+ [![PyPI - Version](https://img.shields.io/pypi/v/x-mcp-server)](https://pypi.org/project/x-mcp-server/)
25
+ [![PyPI Downloads](https://static.pepy.tech/badge/x-mcp-server)](https://pepy.tech/projects/x-mcp-server)
26
+ ![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)
27
+ </div>
28
+
29
+ ---
30
+
31
+ ## What is this?
32
+
33
+ `x-mcp-server` is a Python-based MCP server that connects any MCP-compatible client (Claude Desktop, Cursor, Windsurf) to the X (Twitter) API v2. It lets you post tweets, search, like, retweet, follow users, send DMs, manage bookmarks, and more — all driven by AI through natural language.
34
+
35
+ ---
36
+
37
+ ## Quick Start
38
+
39
+ ```bash
40
+ uvx x-mcp-server@latest
41
+ ```
42
+
43
+ 1. **Get X API credentials** from the [X Developer Portal](https://developer.x.com/)
44
+ 2. **Install `uv`** if you haven't:
45
+ ```bash
46
+ # macOS / Linux
47
+ curl -LsSf https://astral.sh/uv/install.sh | sh
48
+ # Windows
49
+ powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
50
+ ```
51
+ 3. **Set up your `.env`** or environment variables (see [Authentication](#authentication))
52
+ 4. **Check auth:**
53
+ ```bash
54
+ uvx x-mcp-server@latest auth
55
+ ```
56
+ 5. **Run the server:**
57
+ ```bash
58
+ uvx x-mcp-server@latest
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Key Features
64
+
65
+ - **27 Tools** covering tweets, search, users, DMs, bookmarks, lists, and threads
66
+ - **Dual Authentication:** Bearer token (read-only) + OAuth 1.0a (full read-write)
67
+ - **Pagination:** All list operations support cursor-based pagination
68
+ - **Media Upload:** Attach images/videos to tweets via v1.1 media upload
69
+ - **Thread Posting:** Post multi-tweet threads in a single call
70
+ - **Polls:** Create tweets with polls
71
+ - **Stdio & SSE Transports:** Works with Claude Desktop, Cursor, and remote deployments
72
+
73
+ ---
74
+
75
+ ## Authentication
76
+
77
+ ### Environment Variables
78
+
79
+ Set these in a `.env` file or as environment variables:
80
+
81
+ **Read-only** (app-only / Bearer token):
82
+ ```
83
+ BEARER_TOKEN=your-bearer-token
84
+ ```
85
+
86
+ **Full read-write** (OAuth 1.0a user context):
87
+ ```
88
+ CONSUMER_KEY=your-consumer-key
89
+ SECRET_KEY=your-secret-key
90
+ ACCESS_TOKEN=your-access-token
91
+ ACCESS_TOKEN_SECRET=your-access-token-secret
92
+ ```
93
+
94
+ If you have all 5, the Bearer token is used for reads and OAuth 1.0a for writes. If you only have `BEARER_TOKEN`, read operations work but posting/liking/etc. will be unavailable.
95
+
96
+ ### Getting Your Credentials
97
+
98
+ 1. Go to the [X Developer Portal](https://developer.x.com/)
99
+ 2. Create a project and app
100
+ 3. Under **Keys and tokens**:
101
+ - Copy **API Key** → `CONSUMER_KEY`
102
+ - Copy **API Secret** → `SECRET_KEY`
103
+ - Copy **Bearer Token** → `BEARER_TOKEN`
104
+ - Under **Authentication Tokens**, generate **Access Token and Secret** → `ACCESS_TOKEN` + `ACCESS_TOKEN_SECRET`
105
+ 4. Make sure your app has **Read and Write** permissions
106
+
107
+ ### The `auth` Command
108
+
109
+ Verify your credentials are working:
110
+
111
+ ```bash
112
+ uvx x-mcp-server@latest auth
113
+ ```
114
+
115
+ Output:
116
+ ```
117
+ X (Twitter) MCP — Auth check
118
+ BEARER_TOKEN: set
119
+ CONSUMER_KEY: set
120
+ SECRET_KEY: set
121
+ ACCESS_TOKEN: set
122
+ ACCESS_TOKEN_SECRET: set
123
+
124
+ Authenticated as: @yourusername (Your Name)
125
+ Followers: 1234 Following: 567 Tweets: 890
126
+ Bearer token: valid (read operations available)
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Available Tools (27 Total)
132
+
133
+ ### Read Operations
134
+
135
+ - **`x_get_me`** — Get the authenticated user's profile
136
+ - **`x_get_user`** — Look up a user by username
137
+ - `username`: Handle without @ (e.g. `"elonmusk"`)
138
+ - **`x_get_user_by_id`** — Look up a user by numeric ID
139
+ - `user_id`: Numeric user ID
140
+ - **`x_get_tweet`** — Get a single tweet by ID with full content and metrics
141
+ - `tweet_id`: Numeric tweet ID
142
+ - **`x_get_user_tweets`** — Get recent tweets by a user (5-100 per page)
143
+ - `username`, `max_results` (default 10), `pagination_token`
144
+ - **`x_get_user_mentions`** — Get tweets mentioning a user (5-100 per page)
145
+ - `username`, `max_results` (default 10), `pagination_token`
146
+ - **`x_search_tweets`** — Search recent tweets (last 7 days)
147
+ - `query` (supports operators: `from:`, `#hashtag`, `is:reply`, `has:media`)
148
+ - `max_results` (10-100), `sort_order` (`"recency"` or `"relevancy"`), `next_token`
149
+ - **`x_get_home_timeline`** — Get home timeline (requires OAuth 1.0a)
150
+ - `max_results` (1-100, default 20), `pagination_token`
151
+ - **`x_get_followers`** — Get a user's followers (1-1000 per page)
152
+ - `username`, `max_results` (default 20), `pagination_token`
153
+ - **`x_get_following`** — Get who a user follows (1-1000 per page)
154
+ - `username`, `max_results` (default 20), `pagination_token`
155
+ - **`x_get_liked_tweets`** — Get tweets liked by a user (5-100 per page)
156
+ - `username` (optional, defaults to authenticated user), `max_results`, `pagination_token`
157
+ - **`x_get_bookmarks`** — Get bookmarked tweets (requires OAuth 1.0a)
158
+ - `max_results` (1-100, default 20), `pagination_token`
159
+ - **`x_get_owned_lists`** — Get lists owned by a user
160
+ - `username` (optional, defaults to authenticated user)
161
+ - **`x_get_list_tweets`** — Get tweets from an X List (1-100 per page)
162
+ - `list_id`, `max_results` (default 20), `pagination_token`
163
+
164
+ ### Write Operations (require OAuth 1.0a)
165
+
166
+ - **`x_post_tweet`** — Post a new tweet
167
+ - `text` (required), `reply_to_tweet_id`, `quote_tweet_id`, `media_paths`, `poll_options`, `poll_duration_minutes`
168
+ - **`x_delete_tweet`** — Delete your own tweet
169
+ - `tweet_id`
170
+ - **`x_post_thread`** — Post a thread (series of connected tweets)
171
+ - `tweets`: List of tweet texts in order
172
+ - **`x_like_tweet`** / **`x_unlike_tweet`** — Like or unlike a tweet
173
+ - `tweet_id`
174
+ - **`x_retweet`** / **`x_unretweet`** — Retweet or undo retweet
175
+ - `tweet_id`
176
+ - **`x_follow_user`** / **`x_unfollow_user`** — Follow or unfollow by username
177
+ - `username`
178
+ - **`x_bookmark_tweet`** / **`x_remove_bookmark`** — Bookmark or unbookmark a tweet
179
+ - `tweet_id`
180
+
181
+ ### DM Operations (require OAuth 1.0a)
182
+
183
+ - **`x_send_dm`** — Send a direct message
184
+ - `username`, `text`
185
+ - **`x_get_dm_events`** — Get recent DM events (1-100 per page)
186
+ - `max_results` (default 20), `pagination_token`
187
+
188
+ ---
189
+
190
+ ## Usage with Claude Desktop
191
+
192
+ Add to your `claude_desktop_config.json`:
193
+
194
+ <details>
195
+ <summary>Config: uvx (Recommended)</summary>
196
+
197
+ ```json
198
+ {
199
+ "mcpServers": {
200
+ "x": {
201
+ "command": "uvx",
202
+ "args": ["x-mcp-server@latest"],
203
+ "env": {
204
+ "BEARER_TOKEN": "your-bearer-token",
205
+ "CONSUMER_KEY": "your-consumer-key",
206
+ "SECRET_KEY": "your-secret-key",
207
+ "ACCESS_TOKEN": "your-access-token",
208
+ "ACCESS_TOKEN_SECRET": "your-access-token-secret"
209
+ }
210
+ }
211
+ }
212
+ }
213
+ ```
214
+
215
+ macOS note: If you get `spawn uvx ENOENT`, use the full path:
216
+ ```json
217
+ "command": "/Users/yourusername/.local/bin/uvx"
218
+ ```
219
+ </details>
220
+
221
+ <details>
222
+ <summary>Config: Development (from cloned repo)</summary>
223
+
224
+ ```json
225
+ {
226
+ "mcpServers": {
227
+ "x": {
228
+ "command": "uv",
229
+ "args": ["run", "--directory", "/path/to/x-mcp", "x-mcp"]
230
+ }
231
+ }
232
+ }
233
+ ```
234
+ </details>
235
+
236
+ ---
237
+
238
+ ## Usage with Cursor / Windsurf
239
+
240
+ ```json
241
+ {
242
+ "mcpServers": {
243
+ "x": {
244
+ "command": "uvx",
245
+ "args": ["x-mcp-server@latest"],
246
+ "env": {
247
+ "BEARER_TOKEN": "your-bearer-token",
248
+ "CONSUMER_KEY": "your-consumer-key",
249
+ "SECRET_KEY": "your-secret-key",
250
+ "ACCESS_TOKEN": "your-access-token",
251
+ "ACCESS_TOKEN_SECRET": "your-access-token-secret"
252
+ }
253
+ }
254
+ }
255
+ }
256
+ ```
257
+
258
+ ---
259
+
260
+ ## SSE Transport (Remote / Container)
261
+
262
+ ```bash
263
+ uv run x-mcp --transport sse
264
+ ```
265
+
266
+ | Variable | Default | Description |
267
+ |:---------|:--------|:------------|
268
+ | `HOST` / `FASTMCP_HOST` | `0.0.0.0` | Bind address |
269
+ | `PORT` / `FASTMCP_PORT` | `8000` | Listen port |
270
+
271
+ ---
272
+
273
+ ## Environment Variables Reference
274
+
275
+ | Variable | Required | Description |
276
+ |:---------|:---------|:------------|
277
+ | `BEARER_TOKEN` | For reads | X API v2 Bearer Token |
278
+ | `CONSUMER_KEY` | For writes | Consumer Key (API Key) |
279
+ | `SECRET_KEY` | For writes | Secret Key (API Secret) |
280
+ | `ACCESS_TOKEN` | For writes | User Access Token |
281
+ | `ACCESS_TOKEN_SECRET` | For writes | User Access Token Secret |
282
+ | `HOST` / `FASTMCP_HOST` | No | SSE transport bind address (default `0.0.0.0`) |
283
+ | `PORT` / `FASTMCP_PORT` | No | SSE transport port (default `8000`) |
284
+
285
+ ---
286
+
287
+ ## Example Prompts for Claude
288
+
289
+ - "What are the latest tweets about #AI?"
290
+ - "Show me @elonmusk's recent tweets"
291
+ - "Post a tweet saying 'Hello from my AI assistant!'"
292
+ - "Like the latest tweet from @openai"
293
+ - "Search for tweets about machine learning from the past week"
294
+ - "Post a thread about the benefits of open source"
295
+ - "Who are my most recent followers?"
296
+ - "Send a DM to @friend saying 'Hey, let's catch up!'"
297
+ - "Bookmark this interesting tweet for later"
298
+ - "Show me my home timeline"
299
+
300
+ ---
301
+
302
+ ## Contributing
303
+
304
+ Contributions are welcome! Please open an issue to discuss bugs or feature requests. Pull requests are appreciated.
305
+
306
+ ---
307
+
308
+ ## License
309
+
310
+ This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details.
311
+
312
+ ---
313
+
314
+ ## Credits
315
+
316
+ - Built with [FastMCP](https://github.com/jlowin/fastmcp)
317
+ - Uses [Tweepy](https://github.com/tweepy/tweepy) for X API v2 access
318
+ - By [MindMade](https://mindmade.ai)