x-search
Search and analyze X (Twitter) posts via the X API v2 through five MCP tools.
Recent search (
search_recent_posts): find posts from the last 7 days using operators likefrom:,@mention,#hashtag,"exact phrase",url:,lang:,-is:retweet,-is:reply,has:media; paginate withnext_tokenand sort by recency or relevancy (10–100 results).Full-archive search (
search_full_archive_posts): query all historical posts back to March 2006 with ISO 8601start_time/end_timebounds, up to 500 results per page (requires Pro/Academic tier).Post volume trends (
get_post_counts): get time-series counts grouped by day, hour, or minute, over the last 7 days or the full archive, without fetching individual posts.Post lookup (
get_post): fetch a single post's details and engagement metrics (likes, reposts, replies, views, author info) by numeric status ID or full URL.Rate limit check (
check_rate_limits): see remaining quota and reset countdown per endpoint category (search,search_all,tweets,counts).
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.Official MCP SDK, stdio by default: Runs over stdin/stdout for local hosts, with optional Streamable-HTTP and SSE transports for remote/web clients (Google Gemini Spark, hosted agents).
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"
}
}
}
}Remote / Network Deployment (Streamable-HTTP + SSE)
Local hosts launch this server over stdio, which is the default and needs no configuration. Remote clients cannot spawn a subprocess: they need a public HTTPS endpoint speaking JSON-RPC over POST (Streamable-HTTP) or Server-Sent Events.
# Streamable-HTTP + SSE on one port, no auth (put a reverse proxy in front)
x-search --transport both --host 127.0.0.1 --port 8091
# Same, but every request must carry a bearer token
X_SEARCH_HTTP_TOKEN="$(openssl rand -hex 32)" \
x-search --transport both --host 127.0.0.1 --port 8091Endpoint | Purpose |
| Streamable-HTTP JSON-RPC (the modern transport) |
| Legacy HTTP+SSE transport |
| Liveness probe, always unauthenticated |
| RFC 9728 probe, answered with |
Options
Flag | Env var | Default | Notes |
|
|
|
|
|
|
| Bind address for network transports |
|
|
| Bind port for network transports |
|
|
| Streamable-HTTP endpoint path |
|
| off | Omit |
|
| unset | Requires a static |
Connecting Google Gemini Spark
Gemini Spark's custom connected apps are OAuth-only. When you paste an MCP server URL it performs protected-resource discovery (RFC 9728), then authorization-server discovery (RFC 8414), then an authorization-code flow with PKCE. A server that answers "no authorization server here" is rejected with "This URL does not appear to be a valid MCP server" — even when its JSON-RPC endpoint is perfectly healthy.
Setting X_SEARCH_PUBLIC_URL makes this server its own OAuth 2.1 authorization
server:
X_SEARCH_PUBLIC_URL="https://mcp.example.com" \
X_SEARCH_OAUTH_STORE="$HOME/.config/xsearch-oauth.json" \
x-search --transport both --host 127.0.0.1 --port 8091On first start it generates a client ID and secret and persists them. Spark does not need them: it registers itself.
Then, in Settings & help → Connected Apps → Custom apps for Spark → Add a custom app, enter the MCP server URL and click Next:
https://mcp.example.com/mcpLeave "Advanced features" collapsed. That manual-credentials path is only for
servers without Dynamic Client Registration; this server advertises
registration_endpoint, so Spark registers itself.
Why the two metadata fields matter
Two fields in /.well-known/oauth-authorization-server decide whether Spark
accepts the server at all:
Field | Required value | What happens otherwise |
| must include | Spark is a public client. Advertise only |
| present | Without it Spark cannot self-register and falls back to asking for a client ID and secret |
The MCP SDK hardcodes the first field to the two secret-based methods, so
x_search.http_server shadows the SDK's metadata route with its own document
(x_search.oauth.authorization_server_metadata).
What keeps open registration safe
Registration is open to anyone, so the redirect URI is the first gate.
Registrations are only accepted from Google-owned origins — the suffix match
covers oauth-redirect.googleusercontent.com,
oauth-redirect-sandbox.googleusercontent.com and
oauth-redirect-test.googleusercontent.com, which is where all six of Spark's
real redirect URIs live (override with
X_SEARCH_OAUTH_ALLOWED_REDIRECT_ORIGINS). Loopback callbacks are refused unless
X_SEARCH_OAUTH_ALLOW_LOOPBACK=1, and an empty allow-list refuses to start rather
than accepting everything.
The redirect allow-list is necessary but not sufficient, and it is a mistake to
treat it as the security boundary. An authorization code is returned in the
Location header of the authorization response, so a caller that never follows
the redirect can read the code out of its own HTTP response. Origin gating cannot
stop that.
The real gate is the approval step. GET /authorize no longer issues anything:
it redirects the browser to /consent, and a code is only minted when a human
submits the deployment's approval secret. An anonymous caller can register a
client and start a flow, but it cannot approve one.
# read the generated approval secret
python -c "import json,pathlib; print(json.loads(pathlib.Path('$HOME/.config/xsearch-oauth.json').read_text())['pre_registered_client']['consent_secret'])"Override with X_SEARCH_CONSENT_SECRET. When Spark connects it opens the approval
page in a browser; enter the secret there once.
Spark is a public client: real traces show it sending client_id, code,
code_verifier and redirect_uri to /token and no client secret, even when
it was given one to paste in. The pre-registered client is therefore public by
default. Set X_SEARCH_OAUTH_TOKEN_AUTH_METHOD=client_secret_post (or
client_secret_basic) only if you need a genuinely confidential client.
Refresh tokens rotate, but a rotated-out token stays valid for
REFRESH_REUSE_GRACE_SECONDS (120s) so a client holding two connections does not
have its second concurrent refresh rejected.
Reverse proxy
Serve the whole origin — MCP and OAuth — from one host, because the issuer URL in the metadata has to be the URL clients actually reach:
:8092 {
@root_get { method GET; path / }
respond @root_get "x-search MCP endpoint" 200
@health path /health
respond @health "ok" 200
@post_root { method POST; path / }
rewrite @post_root /mcp
@post_sse { method POST; path /sse }
rewrite @post_sse /mcp
reverse_proxy 127.0.0.1:8091 {
header_up Accept "application/json, text/event-stream, */*"
flush_interval -1
}
}Expose port 8092 through a Cloudflare Tunnel to get the HTTPS URL. Two operational notes:
Do not front this with a WAF rule that blocks non-browser user agents — MCP clients are servers, not browsers.
The generated client secret is the credential. Rotate it by deleting the store file and re-adding the app in Gemini.
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).
Search public X (Twitter) posts and read profiles, timelines, followers, trends and X Articles.
Read-only public X (Twitter) data: profiles, tweets, threads, followers, search. Pay per result.
Read public Twitter/X data: tweets, profiles, followers, search. No X developer account.
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.1 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.75 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