Wire TwitterAPIs into Claude, Cursor, and Windsurf
Install the TwitterAPIs MCP server in under two minutes and let your AI agent search tweets, fetch profiles, and read timelines without writing a line of glue code.
The Model Context Protocol (MCP) lets AI coding assistants call external APIs as native tools. Once the TwitterAPIs MCP server is wired in, you can ask Claude or your editor to search for tweets, pull a user profile, or read a timeline in plain English. No OAuth, no SDK, no wrapper code.
Cost: each tool call the agent makes costs the same as a direct API call: $0.0008 per read request ($0.04 per 1,000 tweets, since each call returns about 20 tweets). Write and private-timeline calls are priced separately; see the pricing page.
What you need
- A TwitterAPIs API key. Sign up at twitterapis.com to get $0.50 in free credits.
- Node.js 18+ installed (needed to run the MCP server via
npx). - One of: Claude Desktop, Claude Code, Cursor, Windsurf, or VS Code with the Copilot MCP extension.
You do not need a Twitter/X developer account, OAuth credentials, or any SDK.
How it works
The @twitterapis/mcp package starts a local MCP server. Your editor or Claude client connects to it over stdio and exposes every TwitterAPIs endpoint as a callable tool. When your agent decides to fetch tweets, it calls the tool; the server makes the API request with your key and returns the JSON. You never write the HTTP call yourself.
your prompt --> AI agent --> MCP tool call --> @twitterapis/mcp --> api.twitterapis.com
^
TWITTERAPIS_KEY env var (your key)Step 1: set the environment variable
Export your key once so the server picks it up:
export TWITTERAPIS_KEY="your_api_key_here"For persistent setups, add it to your shell profile or a .env file that your editor reads.
Step 2: add the MCP config
Pick your client below and paste the config. The server runs on demand via npx; nothing is installed globally.
Open ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows). Add the twitterapis entry inside mcpServers:
{
"mcpServers": {
"twitterapis": {
"command": "npx",
"args": ["-y", "@twitterapis/mcp"],
"env": {
"TWITTERAPIS_KEY": "your_api_key_here"
}
}
}
}Restart Claude Desktop after saving. The TwitterAPIs tools appear in the tool list on the next conversation.
Add the server with one command in your project directory:
claude mcp add twitterapis -- npx -y @twitterapis/mcpThen set the key in your shell or pass it inline:
export TWITTERAPIS_KEY="your_api_key_here"Alternatively, add it to .claude/settings.json manually:
{
"mcpServers": {
"twitterapis": {
"command": "npx",
"args": ["-y", "@twitterapis/mcp"],
"env": {
"TWITTERAPIS_KEY": "your_api_key_here"
}
}
}
}Open Cursor Settings (Cmd+Shift+J on macOS), navigate to MCP, and click Add new global MCP server. Paste:
{
"mcpServers": {
"twitterapis": {
"command": "npx",
"args": ["-y", "@twitterapis/mcp"],
"env": {
"TWITTERAPIS_KEY": "your_api_key_here"
}
}
}
}Save and restart Cursor. The server appears in the MCP panel with a green dot when the agent picks it up.
Open Windsurf Settings, go to Cascade and then MCP Servers, and add a new server with:
{
"mcpServers": {
"twitterapis": {
"command": "npx",
"args": ["-y", "@twitterapis/mcp"],
"env": {
"TWITTERAPIS_KEY": "your_api_key_here"
}
}
}
}Restart Windsurf for the server to load. Cascade will list twitterapis among available tools.
Install the GitHub Copilot extension (v1.99+) to get MCP support. Add to your settings.json:
{
"mcp": {
"servers": {
"twitterapis": {
"command": "npx",
"args": ["-y", "@twitterapis/mcp"],
"env": {
"TWITTERAPIS_KEY": "your_api_key_here"
}
}
}
}
}Reload the window. The server shows up in the Copilot Chat tool picker.
Never put your key in source control
The env block in your MCP config is fine for local use, but if you commit config files to a shared repo, use an environment variable reference or a secrets manager instead. The key has billing access.
Step 3: verify the connection
Open a chat with your AI agent and type:
Use the twitterapis tool to fetch the profile for @elonmusk and tell me his follower count.You should see the agent call the user_info tool, get back a JSON response, and summarize it. If it does, the server is wired in and working.
Example agent prompts
Once the server is connected, the agent handles the API calls automatically. These prompts work in any client.
Competitive intelligence
Search for recent tweets mentioning "Stripe API" OR "Stripe developer" that have at least
10 likes. Summarize the top complaints and feature requests you find.The agent calls tweet_advanced_search with query="\"Stripe API\" OR \"Stripe developer\" min_faves:10" and product=Latest. Cost: $0.0008 per page of results.
Audience research
Fetch the last 20 tweets from @levelsio and identify the recurring themes he writes about.
Group them by topic and tell me which ones get the most engagement.The agent calls user_tweets to pull the timeline, then reasons over the results. Cost: $0.0008 per page.
Lead scoring
I have a list of Twitter handles: @johndoe, @janedoe, @acmecorp.
For each one, fetch their profile and recent tweets, then score them 1-10
on how likely they are to be interested in a developer tool for the Twitter API.
Explain your reasoning.The agent calls user_info and user_tweets once per handle. Cost: $0.0016 per handle (2 calls each).
Available tools
The MCP server exposes the full TwitterAPIs surface. Key tools:
| Tool | Underlying endpoint | What it does |
|---|---|---|
tweet_advanced_search | GET /twitter/tweet/advanced_search | Search tweets by query, date, engagement |
user_info | GET /twitter/user/info | Profile by username (followers, bio, metrics) |
user_info_by_id | GET /twitter/user/info_by_id | Profile by numeric user ID |
user_tweets | GET /twitter/user/tweets | A user's recent tweet timeline |
tweet_detail | GET /twitter/tweet/detail | Full tweet data by ID |
tweet_replies | GET /twitter/tweet/replies | Replies to a tweet |
user_followers | GET /twitter/user/followers | Follower list for a handle |
user_following | GET /twitter/user/following | Following list for a handle |
user_mentions | GET /twitter/user/mentions | Tweets mentioning a user |
Write and private-timeline tools (favorite_tweet, home_timeline, etc.) require a customer session. See the authentication guide for details on passing auth_token and ct0.
Direct API calls (no MCP)
If you want to call the API yourself alongside the MCP setup, here are working samples for the search endpoint the agent uses most.
curl "https://api.twitterapis.com/twitter/tweet/advanced_search?query=stripe+api+min_faves%3A10&product=Latest" \
-H "Authorization: Bearer $TWITTERAPIS_KEY"Paginate by appending &cursor=<next_cursor> from the previous response. Each page costs $0.0008.
import os
import requests
API_KEY = os.environ["TWITTERAPIS_KEY"]
BASE_URL = "https://api.twitterapis.com/twitter"
def search_tweets(query: str, max_pages: int = 3) -> list:
"""Search tweets with automatic pagination up to max_pages."""
session = requests.Session()
session.headers.update({"Authorization": f"Bearer {API_KEY}"})
tweets = []
cursor = None
page = 0
while page < max_pages:
params = {"query": query, "product": "Latest"}
if cursor:
params["cursor"] = cursor
resp = session.get(
f"{BASE_URL}/tweet/advanced_search",
params=params,
timeout=15,
)
if resp.status_code == 429:
raise RuntimeError("Rate limited. Back off and retry.")
if resp.status_code == 402:
raise RuntimeError("Credit balance exhausted. Top up at twitterapis.com.")
resp.raise_for_status()
data = resp.json()
tweets.extend(data.get("tweets", []))
page += 1
if not data.get("next_cursor") or not data.get("tweets"):
break
cursor = data.get("next_cursor")
# Cost note: page * $0.0008 per call
print(f"Fetched {len(tweets)} tweets in {page} page(s). Cost: ${page * 0.0008:.4f}")
return tweets
if __name__ == "__main__":
results = search_tweets('"stripe api" min_faves:10 -is:retweet lang:en')
for t in results[:5]:
print(f"@{t['author']['username']}: {t['text'][:100]}")// search.ts
// Run: TWITTERAPIS_KEY=your_key npx tsx search.ts
const API_KEY = process.env.TWITTERAPIS_KEY;
if (!API_KEY) throw new Error("Set TWITTERAPIS_KEY.");
const BASE_URL = "https://api.twitterapis.com/twitter";
interface Tweet {
id: string;
text: string;
author: { username: string; name: string };
favorite_count?: number;
}
interface SearchResponse {
tweets: Tweet[];
next_cursor: string;
}
async function searchTweets(query: string, maxPages = 3): Promise<Tweet[]> {
const tweets: Tweet[] = [];
let cursor: string | null = null;
let page = 0;
while (page < maxPages) {
const url = new URL(`${BASE_URL}/tweet/advanced_search`);
url.searchParams.set("query", query);
url.searchParams.set("product", "Latest");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
if (res.status === 429) throw new Error("Rate limited. Back off and retry.");
if (res.status === 402) throw new Error("Credit exhausted. Top up at twitterapis.com.");
if (!res.ok) throw new Error(`Request failed: ${res.status} ${await res.text()}`);
const data: SearchResponse = await res.json();
tweets.push(...(data.tweets ?? []));
page++;
if (!data.next_cursor || data.tweets.length === 0) break;
cursor = data.next_cursor;
}
// Cost note: page * $0.0008 per call
console.log(`Fetched ${tweets.length} tweets in ${page} page(s). Cost: $${(page * 0.0008).toFixed(4)}`);
return tweets;
}
// Example
const results = await searchTweets('"stripe api" min_faves:10 -is:retweet lang:en');
for (const t of results.slice(0, 5)) {
console.log(`@${t.author.username}: ${t.text.slice(0, 100)}`);
}Error handling reference
| Status | Meaning | Action |
|---|---|---|
200 | OK | Process the response |
400 | Bad query or missing parameter | Check the query string for typos |
401 | Invalid or missing API key | Verify TWITTERAPIS_KEY is set and correct |
402 | Credit balance exhausted | Top up at twitterapis.com |
429 | Rate limited | Wait 60 seconds and retry with exponential backoff |
5xx | Server error | Retry; contact emma@twitterapis.com if persistent |
When the MCP server returns an error, the agent sees the status and message and will usually report it in plain English. You can also check the server logs in your editor's MCP panel.
Troubleshooting
The server does not appear in my client. Confirm Node 18+ is on your PATH (node --version). Some editors require a full restart, not just a reload. Check that the JSON config is valid (no trailing commas).
I see "TWITTERAPIS_KEY is not set". The env block in the config overrides shell env for the child process, so make sure the key is in the config env block rather than only exported in your terminal. Alternatively, set it in your system environment so every process picks it up.
The agent calls the wrong tool. MCP servers expose tool descriptions that guide the model. If the agent picks a generic web-search tool instead of the TwitterAPIs tool, prefix your prompt with "Use the twitterapis tool to..." to anchor it.
Calls are unexpectedly expensive. Check how many pages the agent is fetching. Each page is a separate call. You can instruct the agent: "fetch only the first page, do not paginate."
Next steps
Advanced Tweet Search
Full query-operator syntax, all parameters, and the complete response schema.
Authentication
How bearer auth works and how to add a customer session for write and private endpoints.
Build a brand monitor
Poll advanced search on a schedule, deduplicate, and surface net-new mentions.
Pagination
Walk past the first page with cursor-based pagination.
Post and delete tweets with a session
Register a customer session once with your X credentials, then create and delete tweets programmatically. Full cURL, Python, and Node samples with cost math.
Overview
Search: Full-text and structured search across tweets and users. Filter by query operators, author, date, language, and engagement.