xdataapi.io

MCP server

Give an agent the whole API in one line.

xdataapi.io serves a hosted MCP server at https://api.xdataapi.io/mcp. Transport is Streamable HTTP. Nothing to install, nothing to run, and on most clients nothing to paste: the server implements the MCP authorization flow, so a client signs you in through a browser and gets its own credential. A key in the header works too, and is what a client with no browser needs.

Every tool call is one REST request under the hood, at the same price, through the same cache and rate limit. The agent sees credits_charged and balance_remaining in every result.

Connect

Claude Code

claude mcp add --transport http xdataapi https://api.xdataapi.io/mcp

Claude.ai and Claude Desktop

Add https://api.xdataapi.io/mcp as a custom connector in Settings. These clients have no field for a request header, so this is the only route that reaches them.

Cursor, Windsurf, and other clients with an MCP config file

{
  "mcpServers": {
    "xdataapi": {
      "url": "https://api.xdataapi.io/mcp"
    }
  }
}

Clients that speak stdio only

The mcp-remote bridge speaks stdio to the client and Streamable HTTP to us, and signs in on the client's behalf.

{
  "mcpServers": {
    "xdataapi": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://api.xdataapi.io/mcp"]
    }
  }
}

Connect with a key instead

A client that cannot open a browser — a server, a container, a CI job — sends the key in the same header the REST API takes, or as Authorization: Bearer xd_live_....

claude mcp add --transport http xdataapi https://api.xdataapi.io/mcp --header "x-api-key: xd_live_..."
{
  "mcpServers": {
    "xdataapi": {
      "url": "https://api.xdataapi.io/mcp",
      "headers": { "x-api-key": "xd_live_..." }
    }
  }
}

For mcp-remote, pass the key through the environment. The header is written with no space after the colon: mcp-remote splits the argument on the first colon, and a space there arrives as part of the key.

{
  "mcpServers": {
    "xdataapi": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://api.xdataapi.io/mcp", "--header", "x-api-key:${XDATAAPI_KEY}"],
      "env": { "XDATAAPI_KEY": "xd_live_..." }
    }
  }
}

Signing in, for people writing clients

An unauthenticated call to /mcp answers 401 with a pointer to the discovery chain, which is all a client needs to obtain its own credential:

StepWhere
The challengeWWW-Authenticate: Bearer resource_metadata="..." on the 401
Protected resource (RFC 9728)https://api.xdataapi.io/.well-known/oauth-protected-resource
Authorization server (RFC 8414)https://xdataapi.io/.well-known/oauth-authorization-server
Register a client (RFC 7591)https://xdataapi.io/api/oauth/register
Approvehttps://xdataapi.io/oauth/authorize
Exchange the codehttps://xdataapi.io/api/oauth/token
Disconnect (RFC 7009)https://xdataapi.io/api/oauth/revoke

Clients are public and PKCE is required, with S256 only. There are no scopes: every tool is read-only and there is one level of access, so a scope list would be several words that all mean the same thing.

What the exchange returns is an ordinary API key named after the app. It appears in the dashboard beside keys you made by hand, spends the same balance at the same prices, and stops the moment you revoke it. It does not expire, and there is no refresh token: it is the same class of credential you mint yourself, with the same revocation story.

Tools

ToolArgumentsCredits
get_userhandle1
get_usershandles[], up to 1001 per profile found
get_user_tweetsuser, count, cursor1 per tweet
get_followersuser, count, cursor0.1 per profile
get_follower_idsuser, count, cursor0.02 per id
get_followinguser, count, cursor0.1 per profile
search_tweetsq, product, count, cursor1 per tweet or profile
get_tweetid1
get_tweetsids[], up to 1001 per tweet found
get_threadid, cursor1 per tweet
get_repliesid, cursor1 per reply
get_quotesid, count, cursor1 per tweet
get_retweetersid, count, cursor0.5 per profile
get_balancefree

Every tool takes fresh: true to bypass the cache at 2x. All tools are read-only and idempotent, and are annotated as such, so clients that auto-approve read-only tools do not prompt on every call.

Notes

  • The server is stateless. Each request carries the key; there is no session to expire.
  • A REST error (not_found, no_credits, rate_limited) comes back as a tool error with the same JSON body, so the agent can read the code and act on it.
  • Results are the same flat Tweet and User objects as the REST API, as JSON text.
  • Keys are per account. Create one key per agent in the dashboard so you can revoke it alone.

On this page