x-search
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@x-searchfind recent posts about deepseek in English, no retweets"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
X (Twitter) Search Tool & MCP Server
An asynchronous Model Context Protocol (MCP) server and Antigravity plugin for searching recent and historical posts on X (Twitter), analyzing tweet volume trends, inspecting engagement metrics, looking up individual posts, and managing rate limits via the X API v2.
Features
Recent Search (v2): Search posts from the last 7 days with rich operator support (
from:,to:,@mention,#hashtag,url:,lang:en,-is:retweet,-is:reply,has:media).Full-Archive Search (v2): Search all historical posts back to March 2006 with UTC timestamp bounds (
start_time,end_time) and up to 500 results per page.Post Counts API: Retrieve time-series post volume trends and aggregate counts grouped by
day,hour, orminutefor recent or full-archive data.Hydrated Data: Automatic resolution of author handles, verified badges, profile pictures, and engagement metrics (likes, reposts, replies, views).
Post Lookup: Fetch single posts using either numeric status IDs or full URLs (
https://x.com/...orhttps://twitter.com/...).Rate Limit Tracking: Real-time quota tracking (
x-rate-limit-remaining,x-rate-limit-reset) with actionable countdowns and per-endpoint isolation.FastMCP & stdio: Built on the official Python MCP SDK with stdio transport.
Agent Skill & Antigravity Plugin: Bundled with
plugin.json,mcp_config.json, andskills/x-search/SKILL.mdfor seamless agent workflows.
Related MCP server: x-search-mcp
Quickstart & Installation
1. Prerequisites
Python 3.12+
uvpackage managerAn X API Developer App Bearer Token (obtain from developer.x.com)
2. Configure Credentials
Copy .env.example to .env and set your Bearer Token:
cp .env.example .env
# Edit .env and paste your token:
# X_BEARER_TOKEN="your_token_here"Or export it in your shell environment:
export X_BEARER_TOKEN="your_token_here"3. Install Dependencies
uv syncAntigravity Plugin Installation
Install the plugin directly into Antigravity using the agy CLI:
# From within the repository directory:
agy plugin install .
# Or specify the directory path:
agy plugin install /path/to/x-search-toolVerification & Management
# Validate plugin structure (skills, MCP servers, manifests)
agy plugin validate .
# List installed plugins
agy plugin list
# Enable or disable
agy plugin enable x-search
agy plugin disable x-searchOnce installed, the x-search skill and MCP server are automatically active for all Antigravity agent sessions.
Usage with Other MCP Hosts (Claude Code, Cursor, Windsurf)
Claude Code CLI
claude mcp add x-search uv -- run --directory /path/to/x-search-tool x-searchMCP Configuration File (mcp.json / mcp_config.json)
Add the following entry to your MCP configuration:
{
"mcpServers": {
"x-search": {
"command": "uv",
"args": [
"run",
"--directory",
"/path/to/x-search-tool",
"x-search"
],
"env": {
"X_BEARER_TOKEN": "YOUR_BEARER_TOKEN"
}
}
}
}MCP Tools Reference
search_recent_posts
Searches posts from the last 7 days.
query(str): Search query with optional boolean operators (e.g.,"deepseek" lang:en -is:retweet).max_results(int, optional): Number of posts to return (10 to 100, default: 10).next_token(str, optional): Pagination token for loading subsequent pages.sort_order(str, optional):'recency'or'relevancy'(default:'recency').
search_full_archive_posts
Searches historical posts from March 2006 to present (requires Pro/Academic API tier).
query(str): Search query string (up to 1024 characters).start_time(str, optional): Oldest UTC timestamp in ISO 8601 format (2020-01-01T00:00:00Z).end_time(str, optional): Most recent UTC timestamp in ISO 8601 format.max_results(int, optional): 10 to 500 (default: 10).next_token(str, optional): Pagination token.sort_order(str, optional):'recency'or'relevancy'.
get_post_counts
Analyzes tweet volume trends without fetching individual posts.
query(str): Search query to count matching posts.granularity(str, optional):'day','hour', or'minute'(default:'day').start_time(str, optional): ISO 8601 UTC timestamp.end_time(str, optional): ISO 8601 UTC timestamp.full_archive(bool, optional):Truefor historical counts back to 2006;Falsefor the last 7 days (default).
get_post
Retrieves detailed information for a single post.
post_id_or_url(str): Numeric status ID (e.g.,'1840000000000000001') or full status URL ('https://x.com/user/status/1840000000000000001').
check_rate_limits
Returns remaining API requests and countdown seconds until rate limit reset.
endpoint(str, optional): Endpoint category to inspect:'search'(recent search, default),'search_all'(full archive),'tweets'(post lookup), or'counts'(post volume counts).
Testing & Quality
Run the automated test suite (68 tests):
uv run pytest -vRun code formatting and linting:
uv run ruff check .
uv run ruff format --check .License
This project is licensed under the MIT License - see the LICENSE file for details.
Available Tools
5 toolscheck_rate_limitsA
Check the remaining request quota and reset time for X API endpoints.
Args: endpoint: Endpoint category to inspect: 'search' (recent search), 'search_all' (full archive), 'tweets' (post lookup), or 'counts' (post volume). Default is 'search'.
| Name | Required | Description | Default |
|---|---|---|---|
| endpoint | No | search |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It names the two values returned (remaining quota, reset time), which is useful, and the operation is inherently side-effect-free, but it never states that it is read-only or that it consumes no quota itself. With an output schema present, return-format detail is not required, so this lands at an adequate 3.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose is front-loaded in one sentence, and the Args block is compact and waste-free. Every clause carries information an agent needs to call the tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter, read-only diagnostic tool with an output schema covering the return values, the description supplies purpose and full parameter enumeration. What it lacks is timing guidance for when to invoke it relative to the sibling request tools, which would make it fully self-sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the single parameter has no enum, so the description must compensate — and it does, enumerating all four valid endpoint categories with a parenthetical meaning for each and stating the default ('search'). This adds real meaning beyond the bare string property, though it omits error behavior for invalid values.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: checking remaining request quota and reset time for X API endpoints. The purpose is unambiguous and clearly distinct in kind from the data-fetching siblings, but the description never explicitly contrasts itself with search_recent_posts/get_post/search_full_archive_posts/get_post_counts, so it stops short of full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the nature of a quota-inspection tool, but the description gives no explicit when-to-use guidance (e.g., 'call before issuing requests' or 'after a 429'), nor any when-not condition or named alternative. Context is inferable rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_postA
Fetch details and metrics for a specific post by ID or URL.
Args: post_id_or_url: A numeric post ID (e.g. '1840000000000000001') or a URL (e.g. 'https://x.com/username/status/1840000000000000001').
| Name | Required | Description | Default |
|---|---|---|---|
| post_id_or_url | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses that the result contains 'details and metrics' but says nothing about authentication requirements, rate limiting, or what happens with an invalid or deleted post ID.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core action is front-loaded in a single sentence, and the Args block exists only to give format examples that the schema lacks. Nothing is redundant or padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the single input parameter is fully described. The gaps are the absent auth/rate-limit context and error behavior, which matter given a rate-limit-oriented sibling but are minor for a simple getter.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% (the property is just a bare string), so the description does the work by specifying two accepted formats with concrete examples of a numeric ID and a full status URL. It does not address edge cases such as shortened links or URLs from other domains.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Fetch details and metrics for a specific post') plus the lookup key, which implicitly separates it from the sibling search_* tools and get_post_counts. It never names a sibling explicitly, so differentiation is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the parameter contract: call this when you already have a post ID or URL. There is no explicit when-to-use statement, no named alternatives (e.g. search_recent_posts for discovering posts), and no mention of prerequisites or rate-limit behavior despite check_rate_limits being a sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_post_countsA
Analyze post volume and trend counts on X without fetching individual posts.
Args: query: Search query to count matching posts. granularity: Time bucket grouping: 'day', 'hour', or 'minute' (default: 'day'). start_time: Oldest UTC timestamp in ISO 8601 format (e.g. '2026-09-01T00:00:00Z'). end_time: Most recent UTC timestamp in ISO 8601 format. full_archive: Set to True for historical counts back to 2006 (requires archive access). Default False queries the last 7 days.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| end_time | No | ||
| start_time | No | ||
| granularity | No | day | |
| full_archive | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the behavioral burden, and it does disclose two non-obvious traits: full_archive=True 'requires archive access' (a permission prerequisite) and the default False path only covers 'the last 7 days' (a silent scope limitation). It stops short of covering rate limits or result shape, but the access requirement and default window are exactly the kind of hidden behavior an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in sentence one, followed by a clean Args block that maps one line per parameter with no redundancy. The format is efficient, though the multi-line indentation is slightly heavier than a compact prose description would be.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 5-parameter tool with an output schema (so return values needn't be explained), the description covers formats, defaults, enums, and the archive-access prerequisite. The only real omission is explicit routing against the search_full_archive_posts sibling, which would help disambiguate the two archive-capable tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate entirely, and it does: it documents all five parameters, gives granularity's allowed values ('day', 'hour', 'minute') and default, specifies ISO 8601 UTC format with a concrete example timestamp, and explains the semantic difference between the two full_archive modes. This is meaning well beyond the bare schema types.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence states a specific verb and resource ('Analyze post volume and trend counts on X') and explicitly carves out the boundary 'without fetching individual posts,' which distinguishes it from search_recent_posts, search_full_archive_posts, and get_post. An agent can select this tool over its siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'without fetching individual posts' implies when this tool is preferable to the search siblings, and the full_archive/default-7-days note gives context for the two query modes. However, no sibling tool is named and there is no explicit 'use this when / use X instead' routing, so usage remains inferred rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_full_archive_postsA
Search the complete historical archive of posts on X (Twitter) from March 2006 to present.
Note: Requires an X API account tier with full-archive search access.
Args: query: Search query string (up to 1024 characters). Supports boolean operators. start_time: Oldest UTC timestamp in ISO 8601 format (e.g. '2020-01-01T00:00:00Z'). end_time: Most recent UTC timestamp in ISO 8601 format (e.g. '2020-12-31T23:59:59Z'). max_results: Posts per page (10 to 500, default 10). next_token: Pagination token from previous search result. sort_order: 'recency' or 'relevancy' (default 'recency').
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| end_time | No | ||
| next_token | No | ||
| sort_order | No | recency | |
| start_time | No | ||
| max_results | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full disclosure burden. It usefully flags the account-tier prerequisite and the historical coverage, but says nothing about rate limits (despite a check_rate_limits sibling), pagination behavior beyond the next_token name, or the read-only nature of the call.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose and the access prerequisite before the Args block, and the per-parameter lines are justified because the schema itself carries no descriptions. Slightly list-heavy but every line adds information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be explained, and the description covers the tier prerequisite plus all parameter semantics and pagination via next_token. Only rate-limit behavior is left unaddressed, which is a minor gap given the dedicated sibling tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does thoroughly: character limit and boolean support for query, ISO 8601 format with examples for both timestamps, 10-500 range with default for max_results, and the enum values for sort_order. This fully documents all six parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Search) and resource (complete historical archive of posts on X) with an explicit temporal scope (March 2006 to present). This clearly differentiates it from the sibling search_recent_posts even without naming it directly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an important prerequisite ('Requires an X API account tier with full-archive search access') and the archive scope implicitly frames when this is the right tool versus a recent-posts search. It stops short of explicitly naming search_recent_posts as the alternative and stating the selection condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_recent_postsA
Search recent posts (last 7 days) on X (Twitter).
Supports search operators such as:
from:username (posts by user)
@username (mentions of user)
#hashtag (posts containing hashtag)
"exact phrase" (exact phrase match)
url:domain.com (links to domain)
lang:en (language filter)
-is:retweet (exclude retweets)
-is:reply (exclude replies)
has:images / has:media (media filters)
Args: query: The search query string with optional operators. max_results: Number of posts to retrieve (10 to 100, default 10). next_token: Optional pagination token from a previous search. sort_order: 'recency' or 'relevancy' (default 'recency').
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| next_token | No | ||
| sort_order | No | recency | |
| max_results | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, and it does disclose meaningful operational traits: the 7-day time window, pagination mechanics via next_token, result bounds, and sort modes. It omits rate-limit behavior (relevant given the check_rate_limits sibling) and any auth/error context, but for a search operation the read-only nature is implicit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose statement is front-loaded and the operator list, while long, is high-value syntax the agent cannot get from the schema. The trailing Args section largely restates parameter names but pairs them with the ranges and enum values the schema lacks, so it earns most of its space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described. Query syntax, pagination, result limits, and sorting are all covered, leaving only rate-limit and auth expectations unaddressed — minor gaps for a read-only search tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the Args section fully compensates: it documents query operator syntax, max_results range (10 to 100) and default, next_token's provenance, and the sort_order values 'recency'/'relevancy' — enum values that are absent from the schema entirely. This adds meaning well beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with an explicit scope ('Search recent posts (last 7 days) on X (Twitter)'), which tells an agent exactly what corpus is covered. It does not name or contrast with the obvious sibling search_full_archive_posts, so differentiation is left implicit via the 7-day window rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use/when-not guidance or alternative routing. The '(last 7 days)' scoping implies the boundary against search_full_archive_posts, but the agent must infer that boundary and receives no mention of check_rate_limits despite the sibling existing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.2.0- First observed
check_rate_limits - First observed
get_post - First observed
get_post_counts - First observed
search_full_archive_posts - First observed
search_recent_posts
TDQS
Scored across 5 tools
Each tool targets a distinct resource+action: recent search, archive search, single post lookup, aggregate counts, and rate-limit inspection. The two search tools are clearly separated by their time-range scope (7 days vs. full archive) and descriptions reinforce this distinction.
All names follow a consistent snake_case verb_noun pattern (search_recent_posts, get_post, check_rate_limits, etc.). Minor asymmetry: search_recent_posts carries a 'posts' suffix while search_full_archive_posts does not, and get_post vs. get_post_counts differ in specificity.
Five tools is slightly lean but well-scoped for a read-only search API—each tool earns its place with no redundancy. It could arguably include a user/timeline lookup, but the current count matches the narrow purpose cleanly.
Strong coverage of the search domain: recent search, full-archive search, post lookup, volume counts, and quota checking with pagination and time filters. Gaps exist (no user profile/timeline lookup, no engagement or posting operations) but these are outside the stated 'search' scope and can be worked around via operators.
Maintenance
Related MCP Connectors
X (formerly Twitter): X (formerly Twitter) public and private data API for search, posts (Tweets).
Read-only public X (Twitter) data: profiles, tweets, threads, followers, search. Pay per result.
Twitter: Access real-time Twitter/X data as soon as it's posted! With the Twitter/X AIO API, you.
X (Twitter) data for AI agents: tweets, profiles, followers, search, trends + social listening.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables interaction with X (Twitter) API v2 with multi-user OAuth 2.0 support, allowing users to manage bookmarks, create tweets, and access user information with encrypted token storage and automatic refresh.9 npm-
- FlicenseNot gradedqualityDmaintenanceEnables real-time search of X (Twitter) posts, user timelines, and trends using either xAI's Responses API or the official X API v2.4-
- AlicenseBqualityCmaintenanceEnables access to the X API v2 through MCP, covering 175 of 190 published operations with tools for browsing, calling, posting, searching, and managing posts.78 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables LLMs to read and search X posts, manage users and lists, upload media, and publish posts using the X API v2 with OAuth user context.2MIT