⚡ XActions
📖 Guides & Reference

XActions MCP Server Setup Guide

Use AI agents (Claude, Cursor, Windsurf, GPT) to automate X/Twitter — for free.


x_ask: let the agent read the manual

x_ask answers questions about XActions itself, grounded in the documentation, the skills, the browser scripts and the repository. Use it before guessing at a workflow, inventing a script name, or telling a user something is unsupported.

{ "name": "x_ask", "arguments": { "question": "how do I unfollow everyone?" } }

It returns the written answer, the sources behind it, and the exact runnable action (browser script, CLI command, or another MCP tool). Pass actionsOnly: true to skip the model entirely and get just the matching actions in milliseconds.

It is a read tool: no X session, no account access, no API key. Full guide: Ask XActions.

30-Second Quickstart

# Add to your AI client config, then restart the client
npx xactions-mcp

That's it. XActions will auto-install and start the MCP server.


Getting Your auth_token

Most tools require an X/Twitter session cookie for authentication.

  1. Go to x.com and log in
  2. Open DevTools (F12 or Cmd+Option+I)
  3. Go to ApplicationCookieshttps://x.com
  4. Find the cookie named auth_token
  5. Copy its value (a long hex string)

⚠️ Treat this like a password. Never share it publicly.


Claude Desktop

1. Open config file

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

2. Add XActions

{
  "mcpServers": {
    "xactions": {
      "command": "npx",
      "args": ["-y", "xactions-mcp"],
      "env": {
        "XACTIONS_SESSION_COOKIE": "your_auth_token_here"
      }
    }
  }
}

3. Restart Claude Desktop

Quit and reopen Claude Desktop. You should see XActions tools listed.

Auto-generate config

npx xactions mcp-config

This detects your OS and outputs the correct config snippet. Use --write to write it directly.


Cursor

Add to your Cursor SettingsMCP Servers:

{
  "mcpServers": {
    "xactions": {
      "command": "npx",
      "args": ["-y", "xactions-mcp"],
      "env": {
        "XACTIONS_SESSION_COOKIE": "your_auth_token_here"
      }
    }
  }
}

Or add to .cursor/mcp.json in your project root.


Windsurf

Add to your Windsurf Settings (~/.codeium/windsurf/mcp_config.json):

{
  "mcpServers": {
    "xactions": {
      "command": "npx",
      "args": ["-y", "xactions-mcp"],
      "env": {
        "XACTIONS_SESSION_COOKIE": "your_auth_token_here"
      }
    }
  }
}

VS Code (GitHub Copilot)

Add to your VS Code user settings.json or .vscode/mcp.json:

{
  "mcp": {
    "servers": {
      "xactions": {
        "command": "npx",
        "args": ["-y", "xactions-mcp"],
        "env": {
          "XACTIONS_SESSION_COOKIE": "your_auth_token_here"
        }
      }
    }
  }
}

Local Install (Alternative)

If you prefer a local install instead of npx:

npm install -g xactions

Then use xactions-mcp as the command instead of npx:

{
  "mcpServers": {
    "xactions": {
      "command": "xactions-mcp",
      "env": {
        "XACTIONS_SESSION_COOKIE": "your_auth_token_here"
      }
    }
  }
}

Environment Variables

Variable Required Description
XACTIONS_SESSION_COOKIE For most tools Your X/Twitter auth_token cookie
OPENROUTER_API_KEY For AI tools Free key from openrouter.ai
XACTIONS_MODE No local (default, free) or remote
XACTIONS_MCP_TOOLS No Allowlist of tool or group names to expose (see Tool filtering)
XACTIONS_MCP_EXCLUDE No Denylist of tool or group names to hide; wins over the allowlist
XACTIONS_MCP_REQUIRE_APPROVAL No 1 holds every write tool as a draft until approved (see Approval mode)
XACTIONS_MCP_TOKEN No Bearer token required on /mcp when running with --http
XACTIONS_MCP_HOST No Bind address for --http (default 127.0.0.1)
XACTIONS_HOME No Directory for local state such as mcp-drafts.json (default ~/.xactions)
DEBUG No Set to true for verbose error stacks

Tool filtering

The server ships 149 tools. Most sessions need a handful, and a smaller tool list means a cheaper, more accurate model. Filter with an allowlist, a denylist, or both. Each accepts a comma-separated mix of:

  • tool names such as x_get_profile
  • group names such as read or analytics
  • prefix patterns such as x_get_*

Groups (run npx xactions-mcp --list-groups to see every member):

Group What it covers
read Profiles, followers, tweets, search, threads, media, trends, notifications, x_list_platforms
write Post, reply, quote, like, retweet, bookmark, follow, unfollow, mute, delete, profile edits
dm Send, list, and export direct messages
lists X Lists and their members
spaces Spaces discovery, transcripts, and the live Space agent
analytics Account reports, growth, engagement, sentiment, bots, influencers, history
ai Voice analysis, tweet generation, rewriting, summarising, hashtag suggestions
grok Grok queries and image analysis
automation Auto-like, auto-follow, smart unfollow, auto-comment, bulk execution
monitoring Streams, keyword and account monitors, follower alerts, notifications
workflows Saved workflows, the local scheduler, RSS to tweet drafts
persona The persona autopilot
graph Social graph building and analysis
data Account export and migration, datasets, CRM, teams, format conversion
auth x_login
x402 Paid plugin tools, when a plugin registers them
drafts The four approval tools; these are never filtered out

The rules match xdevplatform/xmcp: an empty allowlist means everything, the denylist always wins, and x_list_drafts, x_approve_draft, x_discard_draft, x_draft_status stay available so pending drafts can never be orphaned. tools/list only returns what passes the filter, and calling a hidden tool returns an error naming the group to enable rather than a generic "unknown tool".

Environment variables (any client):

{
  "mcpServers": {
    "xactions": {
      "command": "npx",
      "args": ["-y", "xactions-mcp"],
      "env": {
        "XACTIONS_SESSION_COOKIE": "your_auth_token_here",
        "XACTIONS_MCP_TOOLS": "read,analytics,x_post_tweet",
        "XACTIONS_MCP_EXCLUDE": "x_get_non_followers"
      }
    }
  }
}

The same thing as CLI flags (Cursor, .cursor/mcp.json):

{
  "mcpServers": {
    "xactions": {
      "command": "npx",
      "args": ["-y", "xactions-mcp", "--tools", "read,analytics", "--exclude", "x_get_*"],
      "env": { "XACTIONS_SESSION_COOKIE": "your_auth_token_here" }
    }
  }
}

Unknown names are reported on stderr at startup and otherwise ignored, so a typo hides nothing silently.


HTTP transport

Stdio is the default and is what Claude Desktop, Cursor, Windsurf, and VS Code speak. For a remote client, a shared team server, or a container, run the Streamable HTTP transport instead:

XACTIONS_MCP_TOKEN=$(openssl rand -hex 24) npx xactions-mcp --http --port 8787 --host 127.0.0.1
  • The MCP endpoint is POST /mcp (plus GET for the event stream and DELETE to end a session). Sessions are managed by the server: the initialize response carries an Mcp-Session-Id header that every later request must echo.
  • GET /health is unauthenticated and reports tool and session counts.
  • XACTIONS_MCP_TOKEN turns on bearer auth for everything under /mcp. Without it the server will still start, but only bind it to loopback (the default). Set a token before you change --host.
  • MCP_TRANSPORT=http and PORT are honoured too, for hosts like Railway that inject them.

Hand-check it with curl:

curl -s -i -X POST http://127.0.0.1:8787/mcp \
  -H "Authorization: Bearer $XACTIONS_MCP_TOKEN" \
  -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'
# copy the mcp-session-id header, then:
curl -s -X POST http://127.0.0.1:8787/mcp \
  -H "Authorization: Bearer $XACTIONS_MCP_TOKEN" -H "Mcp-Session-Id: <id>" \
  -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

Claude Desktop and Cursor connect to a remote MCP server by URL. Cursor .cursor/mcp.json:

{
  "mcpServers": {
    "xactions-remote": {
      "url": "http://127.0.0.1:8787/mcp",
      "headers": { "Authorization": "Bearer your_token_here" }
    }
  }
}

Tool filtering and approval mode apply to every HTTP session exactly as they do on stdio.


Approval mode (draft before you post)

Giving an agent a live posting tool is a leap of faith. Approval mode, borrowed from x-use, removes it: with XACTIONS_MCP_REQUIRE_APPROVAL=1 (or --require-approval) every side-effect tool is held as a draft instead of executed. Posting, replying, quoting, liking, retweeting, bookmarking, following, unfollowing, muting, blocking-style profile changes, DM sending, deleting, scheduling, bulk automation, workflow and persona runs, and joining Spaces are all covered; the exact register is WRITE_TOOLS in src/mcp/tool-groups.js. Read and analytics tools run immediately as before.

A held call returns the draft id:

{
  "held": true,
  "draftId": "3f9c1a2b",
  "tool": "x_post_tweet",
  "args": { "text": "Shipping approval mode today." },
  "createdAt": "2026-08-27T05:15:05.512Z",
  "message": "Approval mode is on. \"x_post_tweet\" was saved as draft 3f9c1a2b and has NOT been executed.",
  "next": "Review with x_draft_status, run with x_approve_draft {\"id\":\"3f9c1a2b\"}, or drop with x_discard_draft."
}

Four tools manage drafts and are always available, whatever the tool filter says:

Tool Does
x_list_drafts List drafts, newest first; optional status of pending, executed, failed, or all
x_draft_status Show one draft with its arguments, state, and result or error
x_approve_draft Execute the stored call exactly as submitted; an already-run draft is refused so nothing posts twice
x_discard_draft Delete a draft without running it

Drafts live in ~/.xactions/mcp-drafts.json (XACTIONS_HOME overrides the directory), written atomically, so a second process, a script, or a person with a text editor can review the queue. The same list, approve, and discard functions are exported from src/mcp/drafts.js for use outside MCP.

Claude Desktop, read-only session that can still queue posts for you to approve elsewhere:

{
  "mcpServers": {
    "xactions": {
      "command": "npx",
      "args": ["-y", "xactions-mcp", "--require-approval"],
      "env": {
        "XACTIONS_SESSION_COOKIE": "your_auth_token_here",
        "XACTIONS_MCP_TOOLS": "read,analytics,write"
      }
    }
  }
}

Cursor, approval on with the drafts reviewed in the same chat:

{
  "mcpServers": {
    "xactions": {
      "command": "npx",
      "args": ["-y", "xactions-mcp"],
      "env": {
        "XACTIONS_SESSION_COOKIE": "your_auth_token_here",
        "XACTIONS_MCP_REQUIRE_APPROVAL": "1"
      }
    }
  }
}

A typical exchange: the agent calls x_post_tweet, gets draft 3f9c1a2b back, and shows you the text. You say "approve it", the agent calls x_approve_draft {"id":"3f9c1a2b"}, and only then does the tweet go out.

Approve drafts from the terminal

You do not have to go back through the agent to release a draft. xactions drafts reads the same mcp-drafts.json the server writes:

xactions drafts list                # id, status, age, tool, argument summary
xactions drafts show 3f9c1a2b       # the full arguments
xactions drafts approve 3f9c1a2b    # runs it through the server's own dispatcher
xactions drafts approve --all       # every pending draft, oldest first
xactions drafts discard 3f9c1a2b    # drop it

This is the setup for a read-only agent session where a person releases posts from a shell: give the agent XACTIONS_MCP_REQUIRE_APPROVAL=1, and review the queue with xactions drafts list whenever you like. Both sides honour XACTIONS_HOME, so point them at the same directory if you have moved it. Full reference: cli-reference.md.


Daily action caps

X suspends accounts that follow, like or post faster than a person could. Its limits are enforced on X's side, but by the time X says "over the limit" the account is already flagged. XActions keeps an agent under the line on purpose: every write tool is charged against a rolling 24 hour budget for its action class, and a call that would go over is refused before anything reaches X.

The ledger lives in ~/.xactions/action-ledger.json (honours XACTIONS_HOME), so a budget spent this morning is still spent after a restart, a crash, or a fresh npx xactions-mcp. A cap that resets when the process does is not a cap.

Nothing needs configuring: the defaults apply the moment the server starts.

x_engage sweeps a whole feed in one call, so it is charged once per enabled action class for its entire limit before the first write, the same way x_bulk_execute is charged for its whole username list. A limit: 100 sweep with like and reply reserves 100 of each. Keep limit to what you mean to spend; a dry run (the default) is charged nothing.

Class Default per 24h Tools charged to it
post 2400 x_post_tweet, x_post_thread, x_create_poll, x_schedule_post, x_publish_article, x_persona_run, x_workflow_run
reply 2400 x_reply, x_quote_tweet, x_auto_comment, x_engage
like 500 x_like, x_auto_like, x_bookmark, x_engage
repost 500 x_retweet, x_auto_retweet, x_engage
follow 400 x_follow, x_auto_follow, x_follow_engagers
unfollow 400 x_unfollow, x_unfollow_non_followers, x_unfollow_all, x_smart_unfollow
dm 500 x_send_dm
block 500 x_block_user
mute 500 x_mute_user, x_unmute_user
delete 2400 x_delete_tweet, x_clear_bookmarks

The published sources are X's own limits page (2,400 posts and 500 direct messages a day, 400 follows a day). Classes X does not publish a number for reuse the closest published figure, deliberately on the low side.

Ask for the remaining budget at any time with the x_action_budget tool, which is always available and never charged:

{
  "account": "nichxbt",
  "windowHours": 24,
  "classes": {
    "follow": { "cap": 400, "used": 37, "remaining": 363, "resetAt": "2026-08-28T09:14:02.113Z" }
  }
}

A refused call answers with the class, the cap, and when the next slot frees, so an agent can wait rather than retry into a suspension:

{
  "error": "Daily cap reached for \"follow\" on account \"nichxbt\": 400/400 in the last 24h.",
  "code": "ACTION_CAP_EXCEEDED",
  "resetAt": "2026-08-28T09:14:02.113Z"
}

Changing the caps

Set XACTIONS_ACTION_CAPS to a JSON object, or write the same shape to ~/.xactions/action-caps.json. A flat map sets every account; an accounts key sets one. 0 disables a class entirely.

XACTIONS_ACTION_CAPS='{"follow":150,"like":300,"accounts":{"brand":{"post":50}}}'

Which account a call is charged to is, in order: the server's account option, XACTIONS_ACCOUNT, the username of the saved session, then default. Approving a held draft is charged the same as running the tool directly, so the approval gate cannot be used to spend past a cap.


Available Tools

Scraping (free, no API key needed)

Tool Description
x_get_profile Get any user's profile (bio, followers, etc.)
x_get_followers Scrape a user's followers list
x_get_following Scrape who a user follows
x_get_tweets Scrape a user's recent tweets
x_search_tweets Search tweets by keyword
x_get_thread Unroll and read an entire thread
x_download_video Extract video download URL from a tweet

Analysis

Tool Description
x_detect_unfollowers Snapshot followers to detect unfollowers over time
x_analyze_sentiment Sentiment analysis (rule-based or LLM)
x_best_time_to_post Find optimal posting times from tweet history
x_competitor_analysis Compare metrics across accounts
x_brand_monitor Monitor brand mentions with sentiment

Actions (require auth_token)

Tool Description
x_follow Follow a user
x_unfollow Unfollow a user
x_like Like a tweet
x_post_tweet Post a tweet
x_post_thread Post a multi-tweet thread
x_reply Reply to a tweet
x_retweet Retweet a tweet
x_bookmark Bookmark a tweet
x_send_dm Send a direct message

AI Tools (require OPENROUTER_API_KEY)

Tool Description
x_analyze_voice Analyze a user's writing style
x_generate_tweet Generate tweets in a user's voice
x_summarize_thread AI-powered thread summarization

Example Prompts

Try these with Claude, Cursor, or any MCP-compatible AI:

Research

"Get the profile and last 20 tweets from @elonmusk. Summarize the main topics."

Growth

"Find everyone I follow who doesn't follow me back. Show me the list sorted by how long ago I followed them."

Content

"Analyze @paulg's writing style, then generate 3 tweet ideas about startups in his voice."

Analytics

"Compare the follower counts, tweet frequency, and engagement of @openai, @anthropic, and @google."

Engagement

"Search for tweets about 'AI agents' from the last day. Like the top 5 most engaging ones."


Troubleshooting

npx xactions-mcp returns 404 / package not found

Make sure you have the latest version. If the xactions-mcp package hasn't been published yet, use either of these alternatives:

# Option 1: Use the -p flag to install from the xactions package
npx -p xactions xactions-mcp

# Option 2: Install globally first
npm install -g xactions
xactions-mcp

For MCP client configs, the -p flag approach:

{
  "mcpServers": {
    "xactions": {
      "command": "npx",
      "args": ["-y", "-p", "xactions", "xactions-mcp"],
      "env": {
        "XACTIONS_SESSION_COOKIE": "your_auth_token_here"
      }
    }
  }
}

"Tool not found" or no tools showing

  1. Make sure the MCP server is configured correctly in your client
  2. Restart your AI client after changing config
  3. Check that Node.js 18+ is installed: node --version

"Could not follow/unfollow/post"

Auth is required for action tools. Make sure XACTIONS_SESSION_COOKIE is set in your MCP config env.

"OPENROUTER_API_KEY required"

AI tools (voice analysis, tweet generation, thread summarization) need an OpenRouter API key. Get a free one at openrouter.ai.

Server won't start

# Test manually
node node_modules/xactions/src/mcp/server.js

# Or if globally installed
xactions-mcp

Browser automation errors

XActions uses Puppeteer for browser automation. If you see Chrome/Chromium errors:

# Install Chromium dependencies (Linux)
npx puppeteer browsers install chrome

Two ways in, and when not to use this server

A 150-tool server is a lot to hand a client that only needs to read one profile. Every tool ships its JSON schema on connect, so the tools/list payload is about 60 KB before any work happens. That is a fair price for a long session or for writes, and a poor one for a single lookup.

XActions offers both lanes from the same install, which is unusual: the CLI runs the same code as the MCP tools, so nothing is lost by choosing it.

xactions profile NASA --compact
xactions tweets NASA --limit 50 --fields id,date,likes,text --compact
xactions analyze NASA SpaceX --compact

--compact prints one record per line as tab-separated key=value pairs, and --fields narrows the columns. One Bash call, no schemas loaded, and jq or wc can finish the job before the answer ever reaches the model.

Use this MCP server when you are writing (posting, following, muting) and want the approval mode gate, or when a session will make enough calls that the schema cost amortises. Use the CLI when you need a few facts and you are done. If you do load the server for a read-only session, narrow it first with tool filtering: XACTIONS_MCP_TOOLS=read.

The full decision table, with the recipes and the exact flags, is in AGENTS.md, which coding agents read automatically.

One-click install: the .mcpb bundle

Instead of editing a JSON config by hand, download xactions-<version>.mcpb from the releases page and drag it onto Claude Desktop > Settings > Extensions.

The bundle carries the server and its production dependencies, so there is no npm install and no absolute path to type. Its manifest declares the settings it needs, and Claude Desktop collects them at install time:

Field What it sets
X session cookie (auth_token) XACTIONS_SESSION_COOKIE, stored by the host as a secret. Leave it empty to run the guest tier
Tool groups to expose XACTIONS_MCP_TOOLS, for example read,analytics
Tool groups to hide XACTIONS_MCP_EXCLUDE, for example write,dm
Hold writes for approval XACTIONS_MCP_REQUIRE_APPROVAL

Browser-driven tools download Chromium into your own puppeteer cache the first time they run; every HTTP tool works without it.

To build the bundle from a clone:

node scripts/build-mcpb.mjs                 # dist/xactions-<version>.mcpb
node scripts/build-mcpb.mjs --manifest-only # write and validate the manifest only

The build stages the payload, installs production dependencies inside the bundle, validates the manifest against the MCPB schema, packs it, then unpacks the result and starts the server from it, so a bundle that cannot launch fails at build time rather than on someone's desktop.



Built by @nichxbt. Apache 2.0 License.

⚡ Free and open source

No API keys, no monthly fees, no signup. Star the repo if it saved you a subscription.

View on GitHub