npm package: @iflow-mcp/infatoshi-x-mcp
Description: MCP server for the X (Twitter) API
Latest version: 1.0.0

# x-mcp

An MCP (Model Context Protocol) server that gives AI agents full access to the X (Twitter) API. Post tweets, search, read timelines, like, retweet, upload media -- all through natural language.

Works with **Claude Code**, **Claude Desktop**, **OpenAI Codex**, **Cursor**, **Windsurf**, **Cline**, and any other MCP-compatible client.

**If you're an LLM/AI agent helping a user set up this project, read [`LLMs.md`](./LLMs.md) for step-by-step instructions you can walk the user through.**

---

## What Can It Do?

| Category | Tools | What You Can Say |
|----------|-------|------------------|
| **Post** | `post_tweet`, `reply_to_tweet`, `quote_tweet`, `delete_tweet` | "Post 'hello world' on X" / "Reply to this tweet saying thanks" |
| **Read** | `get_tweet`, `search_tweets`, `get_timeline`, `get_mentions` | "Show me @elonmusk's latest posts" / "Search for tweets about MCP" |
| **Users** | `get_user`, `get_followers`, `get_following` | "Look up @openai" / "Who does this user follow?" |
| **Engage** | `like_tweet`, `retweet` | "Like that tweet" / "Retweet this" |
| **Media** | `upload_media` | "Upload this image and post it with the caption..." |
| **Analytics** | `get_metrics` | "How many impressions did my last post get?" |

Accepts tweet URLs or IDs interchangeably -- paste `https://x.com/user/status/123` or just `123`.

---

## Setup

### 1. Clone and build

```bash
git clone https://github.com/INFATOSHI/x-mcp.git
cd x-mcp
npm install
npm run build
```

### 2. Get your X API credentials

You need 5 credentials from the [X Developer Portal](https://developer.x.com/en/portal/dashboard). Here's exactly how to get them:

#### a) Create an app

1. Go to the [X Developer Portal](https://developer.x.com/en/portal/dashboard)
2. Sign in with your X account
3. Go to **Apps** in the left sidebar
4. Click **Create App** (you may need to sign up for a developer account first)
5. Give it a name (e.g., `my-x-mcp`)
6. You'll immediately see your **Consumer Key** (API Key), **Secret Key** (API Secret), and **Bearer Token**
7. **Save all three now** -- the secret won't be shown again

#### b) Enable write permissions

By default, new apps only have Read permissions. You need Read and Write to post tweets, like, retweet, etc.

1. In your app's page, scroll down to **User authentication settings**
2. Click **Set up**
3. Set **App permissions** to **Read and write**
4. Set **Type of App** to **Web App, Automated App or Bot**
5. Set **Callback URI / Redirect URL** to `https://localhost` (required but won't be used)
6. Set **Website URL** to any valid URL (e.g., `https://x.com`)
7. Click **Save**

#### c) Generate access tokens (with write permissions)

After enabling write permissions, you need to generate (or regenerate) your Access Token and Secret so they carry the new permissions:

1. Go back to your app's **Keys and Tokens** page
2. Under **Access Token and Secret**, click **Regenerate**
3. Save both the **Access Token** and **Access Token Secret**

If you skip step (b) before generating tokens, your tokens will be Read-only and posting will fail with a 403 error.

### 3. Configure credentials

Copy the example env file and fill in your 5 credentials:

```bash
cp .env.example .env
```

Edit `.env`:

```
X_API_KEY=your_consumer_key
X_API_SECRET=your_secret_key
X_BEARER_TOKEN=your_bearer_token
X_ACCESS_TOKEN=your_access_token
X_ACCESS_TOKEN_SECRET=your_access_token_secret
```

---

## Connect to Your Client

Pick your client below. You only need to follow one section.

### Claude Code

```bash
claude mcp add --scope user x-twitter -- node /ABSOLUTE/PATH/TO/x-mcp/dist/index.js
```

Replace `/ABSOLUTE/PATH/TO/x-mcp` with the actual path where you cloned the repo. Then restart Claude Code.

### Claude Desktop

Add to your `claude_desktop_config.json`:

- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
  "mcpServers": {
    "x-twitter": {
      "command": "node",
      "args": ["/ABSOLUTE/PATH/TO/x-mcp/dist/index.js"],
      "env": {
        "X_API_KEY": "your_consumer_key",
        "X_API_SECRET": "your_secret_key",
        "X_ACCESS_TOKEN": "your_access_token",
        "X_ACCESS_TOKEN_SECRET": "your_access_token_secret",
        "X_BEARER_TOKEN": "your_bearer_token"
      }
    }
  }
}
```

### Cursor

Add to your Cursor MCP config:

- **Global** (all projects): `~/.cursor/mcp.json`
- **Project-scoped**: `.cursor/mcp.json` in your project root

```json
{
  "mcpServers": {
    "x-twitter": {
      "command": "node",
      "args": ["/ABSOLUTE/PATH/TO/x-mcp/dist/index.js"],
      "env": {
        "X_API_KEY": "your_consumer_key",
        "X_API_SECRET": "your_secret_key",
        "X_ACCESS_TOKEN": "your_access_token",
        "X_ACCESS_TOKEN_SECRET": "your_access_token_secret",
        "X_BEARER_TOKEN": "your_bearer_token"
      }
    }
  }
}
```

You can also verify the connection in Cursor Settings > MCP Servers.

### OpenAI Codex

**Option A: CLI**

```bash
codex mcp add x-twitter --env X_API_KEY=your_consumer_key --env X_API_SECRET=your_secret_key --env X_ACCESS_TOKEN=your_access_token --env X_ACCESS_TOKEN_SECRET=your_access_token_secret --env X_BEARER_TOKEN=your_bearer_token -- node /ABSOLUTE/PATH/TO/x-mcp/dist/index.js
```

**Option B: config.toml**

Add to `~/.codex/config.toml` (global) or `.codex/config.toml` (project-scoped):

```toml
[mcp_servers.x-twitter]
command = "node"
args = ["/ABSOLUTE/PATH/TO/x-mcp/dist/index.js"]

[mcp_servers.x-twitter.env]
X_API_KEY = "your_consumer_key"
X_API_SECRET = "your_secret_key"
X_ACCESS_TOKEN = "your_access_token"
X_ACCESS_TOKEN_SECRET = "your_access_token_secret"
X_BEARER_TOKEN = "your_bearer_token"
```

### Windsurf

Add to `~/.codeium/windsurf/mcp_config.json`:

```json
{
  "mcpServers": {
    "x-twitter": {
      "command": "node",
      "args": ["/ABSOLUTE/PATH/TO/x-mcp/dist/index.js"],
      "env": {
        "X_API_KEY": "your_consumer_key",
        "X_API_SECRET": "your_secret_key",
        "X_ACCESS_TOKEN": "your_access_token",
        "X_ACCESS_TOKEN_SECRET": "your_access_token_secret",
        "X_BEARER_TOKEN": "your_bearer_token"
      }
    }
  }
}
```

You can also add it from Windsurf Settings > Cascade > MCP Servers.

### Cline (VS Code)

Open Cline's MCP settings (click the MCP Servers icon in Cline's top nav > Configure), then add to `cline_mcp_settings.json`:

```json
{
  "mcpServers": {
    "x-twitter": {
      "command": "node",
      "args": ["/ABSOLUTE/PATH/TO/x-mcp/dist/index.js"],
      "env": {
        "X_API_KEY": "your_consumer_key",
        "X_API_SECRET": "your_secret_key",
        "X_ACCESS_TOKEN": "your_access_token",
        "X_ACCESS_TOKEN_SECRET": "your_access_token_secret",
        "X_BEARER_TOKEN": "your_bearer_token"
      },
      "alwaysAllow": [],
      "disabled": false
    }
  }
}
```

### Other MCP Clients

This is a standard stdio MCP server. For any MCP-compatible client, point it at:

```
node /ABSOLUTE/PATH/TO/x-mcp/dist/index.js
```

With these environment variables: `X_API_KEY`, `X_API_SECRET`, `X_ACCESS_TOKEN`, `X_ACCESS_TOKEN_SECRET`, `X_BEARER_TOKEN`.

---

## Troubleshooting

### 403 "oauth1-permissions" error when posting
Your Access Token was generated before you enabled write permissions. Go to the X Developer Portal, ensure App permissions are set to "Read and write", then **Regenerate** your Access Token and Secret.

### 401 Unauthorized
Double-check that all 5 credentials in your `.env` are correct and that there are no extra spaces or line breaks.

### 429 Rate Limited
The error message includes exactly when the rate limit resets. Wait until then, or reduce request frequency.

### Reply fails with a permissions/restriction error
As of Feb 2024, X restricts programmatic replies via the API. You can only reply if the original author @mentions you or quotes your post. This applies to Free, Basic, Pro, and Pay-Per-Use tiers (Enterprise is exempt). Use `quote_tweet` as a workaround.

### Server shows "Connected" but tools aren't used
Make sure you added the server with the correct scope (user/global, not project-scoped if you want it everywhere), then restart your client.

---

## Rate Limiting

Every response includes rate limit info: remaining requests, total limit, and reset time. When a limit is hit, you get a clear error with the exact reset timestamp.

## Pagination

List endpoints return a `next_token` in the response. Pass it back to get the next page of results. Works on: `search_tweets`, `get_timeline`, `get_mentions`, `get_followers`, `get_following`.

## Search Query Syntax

The `search_tweets` tool supports X's full query language:

- `from:username` -- posts by a specific user
- `to:username` -- replies to a specific user
- `#hashtag` -- posts containing a hashtag
- `"exact phrase"` -- exact text match
- `has:media` / `has:links` / `has:images` -- filter by content type
- `is:reply` / `-is:retweet` -- filter by post type
- `lang:en` -- filter by language
- Combine with spaces (AND) or `OR`

---

## License

MIT