TwitterAPIs Docs
Guides

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/mcp

Then 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:

ToolUnderlying endpointWhat it does
tweet_advanced_searchGET /twitter/tweet/advanced_searchSearch tweets by query, date, engagement
user_infoGET /twitter/user/infoProfile by username (followers, bio, metrics)
user_info_by_idGET /twitter/user/info_by_idProfile by numeric user ID
user_tweetsGET /twitter/user/tweetsA user's recent tweet timeline
tweet_detailGET /twitter/tweet/detailFull tweet data by ID
tweet_repliesGET /twitter/tweet/repliesReplies to a tweet
user_followersGET /twitter/user/followersFollower list for a handle
user_followingGET /twitter/user/followingFollowing list for a handle
user_mentionsGET /twitter/user/mentionsTweets 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

StatusMeaningAction
200OKProcess the response
400Bad query or missing parameterCheck the query string for typos
401Invalid or missing API keyVerify TWITTERAPIS_KEY is set and correct
402Credit balance exhaustedTop up at twitterapis.com
429Rate limitedWait 60 seconds and retry with exponential backoff
5xxServer errorRetry; 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

On this page