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.
- x_mcp_server-1.4.0/.github/workflows/release.yml +59 -0
- x_mcp_server-1.4.0/.gitignore +9 -0
- x_mcp_server-1.4.0/.python-version +1 -0
- x_mcp_server-1.4.0/LICENSE +21 -0
- x_mcp_server-1.4.0/PKG-INFO +318 -0
- x_mcp_server-1.4.0/README.md +302 -0
- x_mcp_server-1.4.0/pyproject.toml +31 -0
- x_mcp_server-1.4.0/src/x_mcp/__init__.py +17 -0
- x_mcp_server-1.4.0/src/x_mcp/py.typed +0 -0
- x_mcp_server-1.4.0/src/x_mcp/server.py +1342 -0
- x_mcp_server-1.4.0/uv.lock +916 -0
|
@@ -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 @@
|
|
|
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
|
+
[](https://pypi.org/project/x-mcp-server/)
|
|
25
|
+
[](https://pepy.tech/projects/x-mcp-server)
|
|
26
|
+

|
|
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)
|