Metadata-Version: 2.4
Name: spectre-mcp
Version: 1.0.0
Summary: 104 tools for X/Twitter automation — direct GraphQL/REST API, no browser, no API keys, free.
Author: Pranjal Richhariya
License-Expression: MIT
Keywords: agent,ai-agent,automation,mcp,scraper,social-media,twitter,x
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.11
Requires-Dist: curl-cffi>=0.15.0
Requires-Dist: fastmcp>=3.4.2
Requires-Dist: loguru>=0.7.3
Requires-Dist: pydantic>=2.13.4
Requires-Dist: twscrape>=0.19.0
Description-Content-Type: text/markdown

<div align="center">

# Spectre MCP

**104 tools for X/Twitter automation. Direct GraphQL/REST API. No browser. No API keys. Free.**

[![Python 3.11+](https://img.shields.io/badge/python-3.11+-3776AB?style=flat-square&logo=python&logoColor=white)](https://python.org)
[![License: MIT](https://img.shields.io/badge/license-MIT-green?style=flat-square)](LICENSE)
[![MCP Compatible](https://img.shields.io/badge/MCP-compatible-8B5CF6?style=flat-square)](https://modelcontextprotocol.io)
[![PyPI](https://img.shields.io/pypi/v/spectre-mcp?style=flat-square&color=cb3837&label=pypi)](https://pypi.org/project/spectre-mcp/)

[Quick Start](#-quick-start) · [All 104 Tools](#-all-104-tools) · [Why Spectre?](#-why-spectre) · [Safety Guide](#️-safety-guide)

</div>

---

## Why Spectre?

Spectre makes **direct HTTP calls** to X's internal GraphQL and REST APIs. No browser, no Puppeteer, no DOM scraping. It's the fastest and lightest way for AI agents to automate X/Twitter.

| | **Spectre** | **XActions** | **twikit** |
|--|:-:|:-:|:-:|
| **Architecture** | Direct GraphQL/REST API | Puppeteer (headless browser) | Python API wrapper |
| **Speed** | <1s per request | 3-10s (browser startup) | ~1s per request |
| **Memory** | ~10MB | ~200MB+ (Chromium) | ~10MB |
| **MCP Server** | ✅ 104 tools | ⚠️ ~50 API tools + wrappers | ❌ None |
| **Account Pool** | ✅ Multi-account auto-rotation | ❌ Single auth_token | ❌ Single session |
| **Browser Required** | ❌ Never | ✅ Always | ❌ Never |
| **DOM Breakage** | ❌ None | ⚠️ Breaks on UI changes | ❌ None |
| **Media Upload** | ✅ Cookie-based, no API keys | ⚠️ Requires API keys | ❌ |
| **Lists** | ✅ Full CRUD + members + subscribe | ❌ | ❌ |
| **Drafts & Scheduled** | ✅ Full CRUD | ⚠️ Basic | ❌ |
| **Bookmark Folders** | ✅ Full CRUD + timeline | ❌ | ❌ |
| **DM Search** | ✅ All/groups/people | ❌ | ❌ |
| **Community Notes** | ✅ Read + rate | ❌ | ❌ |
| **Highlights** | ✅ Create, delete, get | ❌ | ❌ |
| **Notifications** | ✅ Full timeline | ❌ | ❌ |
| **Language** | Python | JavaScript | Python |

---

## 🚀 Quick Start

### Installation

```bash
# Recommended — isolated, auto-updates
pipx install spectre-mcp

# Alternative
uv tool install spectre-mcp

# Fallback
pip install spectre-mcp
```

### Add Your X Account (one-time)

Get your cookies: **x.com → DevTools (F12) → Application → Cookies → copy `auth_token` and `ct0`**

```bash
spectre add myaccount "auth_token=xxx; ct0=yyy"
```

> `ct0` is 160 hex characters. Double-check you copied the full value.

### Configure Your MCP Client

**Hermes Agent** (`~/.hermes/config.yaml`):
```yaml
mcp_servers:
  spectre:
    command: "uvx"
    args: ["spectre-mcp"]
    timeout: 120
```

**Claude Desktop / Cursor**:
```json
{
  "mcpServers": {
    "spectre": {
      "command": "uvx",
      "args": ["spectre-mcp"]
    }
  }
}
```

> No `uv`? Install it: `curl -LsSf https://astral.sh/uv/install.sh | sh`
> Or use `python3 -m spectre.server` instead of `uvx spectre-mcp`.

### Updating

The MCP server updates automatically via `uvx` (always pulls latest from PyPI). For the CLI:

```bash
pipx upgrade spectre-mcp    # if installed via pipx
uv tool upgrade spectre-mcp  # if installed via uv
```

---

## 📦 All 104 Tools

### Account Pool (5)

Manage multiple X accounts with automatic rotation on rate limits.

| Tool | Description |
|------|-------------|
| `list_accounts()` | List all accounts with status |
| `pool_status()` | Pool health stats |
| `set_active_account(username)` | Set primary account |
| `set_auto_rotate(enabled)` | Enable/disable auto-rotation |
| `remove_account(username)` | ⚠️ Remove account from pool |

### Search (2)

| Tool | Description |
|------|-------------|
| `search(query, limit, mode)` | Search tweets. Supports `from:username`, `since:2026-01-01`, `#hashtag`, `filter:media` |
| `search_users(query, limit)` | Search users by name/keyword |

### Users (12)

| Tool | Description |
|------|-------------|
| `get_user(username)` | User profile by @handle |
| `get_user_tweets(username, limit)` | User's recent tweets |
| `get_user_tweets_and_replies(username, limit)` | User's tweets and replies |
| `get_user_media(username, limit)` | User's photos/videos/GIFs |
| `get_followers(username, limit)` | User's followers |
| `get_following(username, limit)` | Who a user follows |
| `get_user_likes(user_id, limit)` | Get a user's liked tweets |
| `get_user_highlights(user_id, limit)` | Get user's highlighted tweets |
| `get_verified_followers(user_id, limit)` | Get Blue-verified followers |
| `get_followers_you_know(user_id, limit)` | Get mutual followers |
| `get_list_memberships(user_id, limit)` | Lists a user is a member of |
| `get_list_ownerships(user_id, limit)` | Lists owned by a user |

> **Note:** `get_list_memberships` and `get_list_ownerships` may return empty due to a known X API server-side issue.

### Tweets (8)

| Tool | Description |
|------|-------------|
| `get_tweet(tweet_id)` | Single tweet by ID |
| `get_tweet_replies(tweet_id, limit)` | Replies to a tweet |
| `get_thread(tweet_id, limit)` | Full conversation thread |
| `get_retweeters(tweet_id, limit)` | Users who retweeted |
| `get_favoriters(tweet_id, limit)` | Users who liked a tweet |
| `get_tweet_edit_history(tweet_id)` | Edit history of a tweet |
| `get_similar_posts(tweet_id, limit)` | Get similar/related posts |
| `get_community_notes(tweet_id)` | Get community notes on a tweet |

### Timeline & Notifications (3)

| Tool | Description |
|------|-------------|
| `get_trends(category, limit)` | Trending topics |
| `get_home_timeline(limit)` | Home feed |
| `get_notifications(limit)` | Notifications timeline |

### Post & Media (3)

| Tool | Description |
|------|-------------|
| `post_tweet(text, reply_to?, quote_tweet?, media_ids?)` | Post a tweet with optional media |
| `upload_media(file_path)` | Upload image or video (jpg, png, gif, mp4, mov) — no API keys needed |
| `delete_tweet(tweet_id)` | ⚠️ Delete a tweet |

### Engagement (6)

| Tool | Description |
|------|-------------|
| `like_tweet(tweet_id)` | Like a tweet |
| `unlike_tweet(tweet_id)` | Unlike a tweet |
| `retweet(tweet_id)` | Retweet |
| `unretweet(tweet_id)` | Undo retweet |
| `bookmark_tweet(tweet_id)` | Bookmark a tweet |
| `unbookmark_tweet(tweet_id)` | Remove bookmark |

### Social (6)

| Tool | Description |
|------|-------------|
| `follow_user(user_id)` | ⚠️ Follow a user |
| `unfollow_user(user_id)` | ⚠️ Unfollow a user |
| `mute_user(user_id)` | Mute a user |
| `unmute_user(user_id)` | Unmute a user |
| `block_user(user_id)` | ⚠️ Block a user |
| `unblock_user(user_id)` | ⚠️ Unblock a user |

### Social Extended (3)

| Tool | Description |
|------|-------------|
| `remove_follower(user_id)` | ⚠️ Remove a follower |
| `pin_reply(tweet_id)` | Pin a reply to a conversation |
| `unpin_reply(tweet_id)` | Unpin a reply |

### DMs (9)

| Tool | Description |
|------|-------------|
| `send_dm(user_id, text)` | ⚠️ Send a direct message |
| `get_dm_inbox(limit)` | Get recent DM conversations |
| `get_dm_conversation(conversation_id, limit)` | Get messages in a conversation |
| `search_dm(query, limit)` | Search all DMs by text |
| `search_dm_groups(query, limit)` | Search DMs in group conversations |
| `search_dm_people(query, limit)` | Search for people in DMs |
| `get_dm_muted(limit)` | Get muted DM conversations |
| `dm_block_user(user_id)` | Block a user in DMs |
| `dm_unblock_user(user_id)` | Unblock a user in DMs |

### Lists (10)

Full lifecycle: create → manage members → subscribe → delete.

| Tool | Description |
|------|-------------|
| `create_list(name, description)` | Create a new list |
| `update_list(list_id, name, description)` | Update list details |
| `delete_list(list_id)` | ⚠️ Delete a list |
| `add_list_member(list_id, user_id)` | Add user to list |
| `remove_list_member(list_id, user_id)` | Remove user from list |
| `get_list_timeline(list_id, limit)` | Tweets from a list |
| `get_list_members(list_id, limit)` | Members of a list |
| `get_list_subscribers(list_id, limit)` | List subscribers |
| `subscribe_list(list_id)` | Subscribe to a list |
| `unsubscribe_list(list_id)` | Unsubscribe from a list |

### Bookmark Folders (8)

| Tool | Description |
|------|-------------|
| `get_bookmark_folders()` | List all bookmark folders |
| `create_bookmark_folder(name)` | Create a folder |
| `edit_bookmark_folder(folder_id, name)` | Rename a folder |
| `delete_bookmark_folder(folder_id)` | ⚠️ Delete a folder |
| `add_tweet_to_folder(folder_id, tweet_id)` | Add tweet to folder |
| `remove_tweet_from_folder(folder_id, tweet_id)` | Remove tweet from folder |
| `get_bookmark_folder_timeline(folder_id, limit)` | Get tweets in a folder |
| `search_bookmarks(query, limit)` | Search bookmarks by text |

> **Note:** Bookmark folders require a bookmark to exist first. Use `bookmark_tweet()` before testing folder operations.

### Bookmarks (2)

| Tool | Description |
|------|-------------|
| `get_bookmarks(limit)` | Your bookmarked tweets |
| `clear_all_bookmarks()` | ⚠️ Delete ALL bookmarks |

### Scheduled Tweets (4)

| Tool | Description |
|------|-------------|
| `schedule_tweet(text, execute_at, reply_to?)` | Schedule a tweet for future posting |
| `get_scheduled_tweets()` | List all scheduled tweets |
| `edit_scheduled_tweet(id, text, execute_at)` | Edit a scheduled tweet |
| `delete_scheduled_tweet(tweet_id)` | ⚠️ Delete a scheduled tweet |

### Draft Tweets (4)

| Tool | Description |
|------|-------------|
| `create_draft(text)` | Save a tweet draft |
| `get_drafts()` | List all drafts |
| `edit_draft(draft_id, text)` | Edit a draft |
| `delete_draft(tweet_id)` | ⚠️ Delete a draft |

### Communities (4)

| Tool | Description |
|------|-------------|
| `get_community_info(community_id)` | Community details |
| `get_community_tweets(community_id, limit)` | Community feed |
| `join_community(community_id)` | Join a community |
| `leave_community(community_id)` | ⚠️ Leave a community |

### Topics (3)

| Tool | Description |
|------|-------------|
| `get_topic_info(topic_id)` | Get topic details |
| `follow_topic(topic_id)` | Follow a topic |
| `unfollow_topic(topic_id)` | Unfollow a topic |

### Community Notes (2)

| Tool | Description |
|------|-------------|
| `get_community_notes(tweet_id)` | Get community notes on a tweet |
| `rate_community_note(note_id, rating)` | Rate a note as helpful/not_helpful |

> **Note:** Community Notes creation requires an eligible account (6+ months old, verified phone, enrolled in the program). This tool is not included in the current release.

### Account Settings & Profile (5)

| Tool | Description |
|------|-------------|
| `get_account_settings()` | View account settings |
| `update_profile(name?, bio?, location?, website?)` | Update profile info |
| `update_profile_image(file_path)` | ⚠️ Change avatar image |
| `update_profile_banner(file_path)` | ⚠️ Change banner image |
| `delete_profile_banner()` | ⚠️ Remove banner |

### Pin & Highlights (5)

| Tool | Description |
|------|-------------|
| `pin_tweet(tweet_id)` | ⚠️ Pin tweet to profile (replaces existing) |
| `unpin_tweet(tweet_id)` | Unpin tweet |
| `create_highlight(tweet_ids)` | ⚠️ Add tweets to profile highlights |
| `delete_highlight(highlight_id)` | ⚠️ Remove a highlight |
| `get_user_highlights(user_id, limit)` | Get user's highlighted tweets |

### Safety & Privacy (4)

| Tool | Description |
|------|-------------|
| `get_muted_accounts(limit)` | List all muted accounts |
| `get_blocked_accounts(limit)` | List all blocked accounts |
| `get_verified_followers(user_id, limit)` | Get Blue-verified followers |
| `get_user_likes(user_id, limit)` | Get a user's liked tweets |

---

## ⚠️ Safety Guide

Spectre marks every destructive tool with **⚠️**. Agents should respect these warnings.

### Always Confirm Before Calling

| Tool | Why |
|------|-----|
| `post_tweet` | Public, live immediately |
| `delete_tweet` | Permanent |
| `pin_tweet` | Replaces existing pin silently |
| `update_profile*` | Changes your public profile |
| `follow_user` / `unfollow_user` | Visible to the other user |
| `block_user` | Blocked user loses access to your content |
| `send_dm` | Sent immediately, no recall |
| `create_highlight` | Adds to your public profile |

### Safe to Use Freely (Read-Only)

All `get_*`, `search_*`, `list_*` tools. `pool_status`, `get_muted_accounts`, `get_blocked_accounts`, `get_scheduled_tweets`, `get_drafts`, `get_bookmarks`, `get_trends`, `get_home_timeline`, `get_notifications`.

### Rate Limits

- ~300 requests/hour/account
- Spectre auto-rotates to the next account on rate limits
- Use `set_auto_rotate(false)` to lock to a single account
- Rate limit errors include `retry_after_seconds`

---

## X Query Operators

| Operator | Example | Description |
|----------|---------|-------------|
| `from:username` | `from:elonmusk` | Tweets by a user |
| `since:YYYY-MM-DD` | `since:2026-01-01` | After date |
| `until:YYYY-MM-DD` | `until:2026-06-01` | Before date |
| `#hashtag` | `#python` | Hashtag search |
| `filter:media` | `AI filter:media` | Only media tweets |
| `filter:links` | `AI filter:links` | Only tweets with links |
| `lang:en` | `AI lang:en` | Language filter |
| `min_retweets:N` | `AI min_retweets:100` | Minimum retweets |
| `min_faves:N` | `AI min_faves:50` | Minimum likes |
| `-"term"` | `AI -"GPT"` | Exclude term |
| `OR` | `python OR rust` | Either term |

---

## CLI

```bash
spectre add <username> <cookies>     Add account via browser cookies
spectre remove <username>            Remove an account
spectre list                         List all accounts
spectre status                       Pool health check
spectre serve                        Start MCP server (default)
spectre help                         Show help
```

---

## Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `SPECTRE_DB` | `~/.spectre/accounts.db` | Account pool path |
| `SPECTRE_PROXY` | none | Global proxy (`socks5://user:pass@host:port`) |
| `TWS_HTTP_BACKEND` | `httpx` | Set to `curl` for TLS fingerprinting |
| `TWS_TELEMETRY` | `0` | Disable telemetry |
| `SPECTRE_OP_*` | built-in | Override GraphQL operation IDs (when they rotate) |

---

## Limitations

- **Authenticated accounts required** — X blocks unauthenticated access
- **Rate limited** — ~300 requests/hour/account (rotation handles this)
- **~3200 tweet cap** on user timelines (X's own limit)
- **ToS risk** — automated access violates X's terms
- **Cookies expire** — re-add every ~2 weeks when searches return empty

---

## License

MIT
