@xcrap/mcp
OfficialClick 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., "@@xcrap/mcpUnroll this thread and summarize it: https://x.com/jack/status/20"
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.
@xcrap/mcp
Twitter / X tools for LLM agents. An MCP server that lets Claude, Cursor, or any other MCP client search posts, read posts and their replies, unroll threads, extract profiles, timelines, account histories and follower lists, list media and check trends on X — without an X account, an API key, or a login.
It wraps the public XCrap API. Twelve tools, one per endpoint, stdio transport, no credentials to configure.
Quick start
npx -y @xcrap/mcpThat is the whole installation. The server talks to https://xcrap.cc, and there is nothing to configure.
Claude Code
claude mcp add xcrap -- npx -y @xcrap/mcpMake it available in every project rather than just this one:
claude mcp add xcrap --scope user -- npx -y @xcrap/mcpThen check it connected:
claude mcp listClaude Desktop
Edit claude_desktop_config.json — macOS: ~/Library/Application Support/Claude/claude_desktop_config.json, Windows: %APPDATA%\Claude\claude_desktop_config.json, Linux: ~/.config/Claude/claude_desktop_config.json — and add:
{
"mcpServers": {
"xcrap": {
"command": "npx",
"args": ["-y", "@xcrap/mcp"]
}
}
}Restart Claude Desktop. The tools appear under the connectors icon in the prompt box.
Cursor
Create .cursor/mcp.json in the project (or ~/.cursor/mcp.json for every project):
{
"mcpServers": {
"xcrap": {
"command": "npx",
"args": ["-y", "@xcrap/mcp"]
}
}
}Then enable xcrap in Settings → Tools & Integrations → MCP.
Any other MCP client
The server speaks MCP over stdio. Run npx -y @xcrap/mcp, or node /path/to/mcp/src/index.js from a checkout.
Related MCP server: x-mcp-server
Tools
Tool | What it does |
| One post by URL or id: text, author, timestamp, metrics, media, poll, quote, community note. |
| Unrolls a whole thread from any post in it, in order, author's posts only. |
| A public profile: bio, location, website, join date, verification, follower counts. |
| A page of an account's posts, newest first, cursor-paginated. |
| Full-text search over X posts with X's own operators, latest, top, photos or videos. |
| Up to 200 of an account's posts in one call, optionally inside a date window. |
| The replies to a post, most liked or newest first (one page, no paging). |
| One page of the accounts following an account, as profiles, cursor-paginated. |
| One page of the accounts an account follows, as profiles, cursor-paginated. |
| What is trending on X right now, with post volumes. |
| Every image, video and GIF on a post, with dimensions, alt text and direct download URLs. |
| Up to 50 posts in a single call — the right tool for a list of links. |
Every tool is read-only. Nothing here posts, likes, follows, or modifies anything on X.
Examples
Ask your client in plain language — it picks the tool:
"Unroll this thread and summarise the argument: https://x.com/jack/status/20" →
xcrap_get_thread"What has @NASA posted this week, images only?" →
xcrap_get_user_tweetswithmedia_only: true"Get me the video from this post" →
xcrap_list_media, then hand over thedownload_url"Pull all 30 of these links into one summary" →
xcrap_bulk(one call, not thirty)"How many followers does @jack have?" →
xcrap_get_user"What are people on X saying about the Starship launch?" →
xcrap_searchwithfeed: "top""What are the replies saying about this post?" →
xcrap_get_replies"Everything @naval posted in March" →
xcrap_get_user_historywithsinceanduntil
Configuration
Variable | Default | Purpose |
|
| API origin. Leave it unset; change it only to route requests through a proxy you control. |
There is no API key. XCrap is free and unauthenticated.
Design notes
Markdown by default, not JSON. Every tool that renders posts defaults to format: "markdown", because a tool result is spent directly out of the model's context window and XCrap's markdown rendering of a post is roughly a tenth the size of the same post as JSON — the JSON carries every null metric, every media variant and every entity offset, none of which a summarising model reads. Pass format: "json" when you genuinely need field-level access: numeric ids, media URLs, per-metric values. xcrap_list_media always returns JSON, because file URLs are field-level data.
Hard 25,000-character cap. No tool result can exceed it. When a response is cut, the model is told so explicitly, with the reason and the argument to change — a truncated answer that looks complete is worse than an error. Pagination cursors are lifted out before the cut so a truncated timeline can still be continued.
Errors are instructions, not status codes. A 404 says the post is deleted, private, or never existed and that retrying will not help. A 429 reports the retry-after window and which endpoint budget was hit. A 451 explains that the account opted out of extraction and must not be worked around. A 502 says every upstream source failed and is usually transient.
Provenance. XCrap reads from four upstream sources in a cascade and caches for five days. Each result carries a one-line footer saying which source answered and whether it came from cache, so the model knows whether it is looking at live data.
Rate limits
Per IP, enforced by the XCrap instance:
Endpoint | Budget |
| 60 / minute |
| 20 / minute |
| 30 / minute |
| 10 / 5 minutes (up to 50 posts each) |
| 20 / minute |
| 5 / 5 minutes |
| 15 / 15 minutes |
| 120 / minute |
Prefer one xcrap_bulk call over many xcrap_get_tweet calls: it is one request instead of N, and it runs them concurrently.
Development
cd mcp
npm install
npm start # run over stdio
npm run inspect # MCP Inspector UI
npm run check # syntax checkRaw stdio round-trip, no client required:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"cli","version":"1.0.0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
| node src/index.jsRequires Node 20 or newer (built-in fetch, no HTTP dependency).
Ethics and limits
XCrap reads only public data, honours account opt-outs (a 451 is final and this server will not route around it), and stores nothing beyond a short cache. It cannot read protected accounts, direct messages, or anything behind a login — and neither can this server.
Links
XCrap: https://xcrap.cc · API docs: https://xcrap.cc/docs
Model Context Protocol: https://modelcontextprotocol.io
MIT licensed.
Available Tools
12 toolsxcrap_bulkFetch many X posts at onceARead-onlyIdempotent
Resolve up to 50 post URLs or ids in a single call.
This is the right tool whenever you have more than two or three links. One bulk call costs one request against a 10-per-5-minutes budget, while the same posts fetched individually cost one request each against a 60-per-minute budget — and bulk runs them concurrently, so it is several times faster.
Failures are per item, not per request: one dead link in a batch of fifty returns forty-nine posts and one error entry, so a single bad URL never loses the batch.
When to use this instead of the alternatives:
Use this for a list of links, a set of ids extracted from a document, or a batch job.
Use xcrap_get_tweet for a single post — bulk uses a cheaper, lighter source and returns slightly less detail per post (no media variants or entity offsets).
Use xcrap_get_thread for connected posts by one author; bulk does not know they are a thread.
Args:
urls (string[], required): 1-50 post URLs or numeric ids. Duplicates are removed by the server.
Returns markdown: a summary line of requested/succeeded/failed, then each post rendered in order, with an explicit error line for any that could not be resolved.
Errors: passing more than 50 URLs is rejected before any request is made — split the list into batches of 50.
| Name | Required | Description | Default |
|---|---|---|---|
| urls | Yes | Post URLs or numeric ids to resolve, 1-50 per call. Mixed forms are fine: ["https://x.com/jack/status/20", "20"]. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, but the description adds substantial behavioral context: per-item failure (one dead link doesn't lose the batch), concurrency, request-cost/budget comparison, duplicate removal, and server-side rejection of >50 URLs. These go well beyond what annotations convey and are crucial for correct invocation.
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 description is well-structured with clear sections (main purpose, usage context, alternatives, args, returns, errors) and every sentence contributes meaningful information. It is front-loaded with the primary purpose and a direct usage guideline, and there is no filler or redundancy.
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?
Given the tool's complexity—batch processing, partial failures, rate limits, and a markdown return format—the description covers all necessary aspects: what it does, when to use it, how failures behave, input constraints, and even the return format. There is no output schema, so the description appropriately explains the markdown structure. Nothing an agent needs to call it correctly is missing.
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 100% and the single `urls` parameter already includes a detailed description covering mixed forms and 1-50 limit. The description adds the 'Duplicates are removed by the server' behavior and clarifies that numeric ids are accepted, providing extra semantic value beyond the schema alone. Slightly above the baseline of 3.
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 description states a specific verb ('resolve'), resource ('post URLs or ids'), and a clear scope ('up to 50 in a single call'). It also distinguishes itself from siblings by naming xcrap_get_tweet and xcrap_get_thread explicitly, so an agent can tell exactly what this tool does and what it does not do.
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?
It explicitly says 'This is the right tool whenever you have more than two or three links' and provides clear when-to-use-this vs. when-to-use-alternatives: use xcrap_get_tweet for a single post and xcrap_get_thread for connected posts. This is unambiguous guidance with no room for inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
xcrap_get_followersList who follows an X accountARead-only
Fetch one page of the accounts following an X/Twitter account, each with its name, handle, bio, follower count and verification.
Use this for "who follows @x", "who does @x follow", or to find the other accounts in someone's circle. X decides the page size (usually a few dozen accounts); pass next_cursor to continue, and stop when it is null.
When to use this instead of the alternatives:
Use xcrap_get_user for one account's own profile and follower count, rather than the list of accounts.
Args:
handle (string, required): "jack", "@jack" or a profile URL.
cursor (string): the next_cursor from a previous call. Omit for the first page. Do not invent one.
format ('markdown' | 'json'): default 'markdown'.
Returns markdown: a heading, then one line per account — name, handle, follower count — with its bio underneath, and a "Next page" cursor line when there is more. Returns json: { handle, relation, count, next_cursor, users[ ] }.
Costs 20 calls/minute. Protected accounts return 404; accounts that opted out of XCrap are left out of the list.
| Name | Required | Description | Default |
|---|---|---|---|
| cursor | No | Pagination cursor from a previous call. Omit for the first page; never construct one by hand. | |
| format | No | Output format. 'markdown' (default) is compact, human-readable and costs roughly a tenth of the tokens of the same data as JSON — prefer it for reading and summarising. Use 'json' only when you need exact field access: numeric ids, media URLs, per-metric values, or provenance metadata. | markdown |
| handle | Yes | X handle, @handle or profile URL whose followers to list. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly and non-destructive annotations, the description discloses one-page pagination, next_cursor semantics, X-controlled page size, the 20 calls/minute rate limit, 404s for protected accounts, and omission of opted-out accounts. It also specifies the distinct markdown and JSON return shapes, giving agents concrete behavioral expectations.
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 description is front-loaded with the core action and organized into use-case, args, returns, and caveat sections, so its length is mostly justified by information content. It loses a point for repeating some schema/args details and including the inaccurate 'who does @x follow' phrasing, which makes it not perfectly lean.
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 three parameters and no output schema, the description supplies everything needed to call the tool correctly: required and optional argument semantics, pagination stop condition, return structures for both formats, rate limit, and known error/omission behavior. Nothing significant is missing.
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?
The input schema already provides 100% coverage with detailed descriptions for all three parameters, including accepted handle formats, cursor construction warnings, and the format enum tradeoffs. The Args section mostly restates that structured information, adding little parameter-level meaning beyond the 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?
The opening sentence states a precise verb and object: 'Fetch one page of the accounts following an X/Twitter account' and lists the returned fields, so the core purpose is clear. It also names xcrap_get_user as a distinct alternative. However, the later line including 'who does @x follow' blurs the relation, since that phrasing describes xcrap_get_following rather than the follower list.
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 description has an explicit 'When to use this instead of the alternatives' section that correctly routes single-profile/follower-count requests to xcrap_get_user. It also gives query phrasings and pagination guidance. Still, it tells agents to use this tool for 'who does @x follow' and never mentions the xcrap_get_following sibling, so the guidance is not fully reliable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
xcrap_get_followingList who an X account followsARead-only
Fetch one page of the accounts followed by an X/Twitter account, each with its name, handle, bio, follower count and verification.
Use this for "who follows @x", "who does @x follow", or to find the other accounts in someone's circle. X decides the page size (usually a few dozen accounts); pass next_cursor to continue, and stop when it is null.
When to use this instead of the alternatives:
Use xcrap_get_user for one account's own profile and follower count, rather than the list of accounts.
Args:
handle (string, required): "jack", "@jack" or a profile URL.
cursor (string): the next_cursor from a previous call. Omit for the first page. Do not invent one.
format ('markdown' | 'json'): default 'markdown'.
Returns markdown: a heading, then one line per account — name, handle, follower count — with its bio underneath, and a "Next page" cursor line when there is more. Returns json: { handle, relation, count, next_cursor, users[ ] }.
Costs 20 calls/minute. Protected accounts return 404; accounts that opted out of XCrap are left out of the list.
| Name | Required | Description | Default |
|---|---|---|---|
| cursor | No | Pagination cursor from a previous call. Omit for the first page; never construct one by hand. | |
| format | No | Output format. 'markdown' (default) is compact, human-readable and costs roughly a tenth of the tokens of the same data as JSON — prefer it for reading and summarising. Use 'json' only when you need exact field access: numeric ids, media URLs, per-metric values, or provenance metadata. | markdown |
| handle | Yes | X handle, @handle or profile URL whose following to list. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds meaningful behavior beyond the annotations: this is a one-page fetch, X decides the page size, continuation uses a cursor, the cursor must come from prior results and stops at null, protected accounts have a 404, opted-out accounts are omitted, and the rate limit is 20 calls/minute. All of this is genuine behavioral detail that cannot be inferred from readOnlyHint/openWorldHint.
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 description is organized clearly with purpose first, then use context, alternatives, args, return values, and operational notes. It is somewhat longer than needed and the 'Args' section duplicates schema field details, but the content is informative, scannable, and sections are labeled. This is efficient communication rather than rambling.
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?
Without an output schema, the description fully explains the markdown and JSON return shapes, the pagination termination condone, and the conditions under which accounts may be missing or errors (404, opted-out accounts). It also states the rate limit. An agent has enough information to invoke the tool correctly and understand each response field.
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?
Input schema descriptions cover all three parameters in detail, so the baseline is 3. The description restates handle forms ('jack', '@jack', URL) and cursor use, but most of these details already exist in the schema. It does reinforce the 'don't invent a cursor' rule and adds a friendly type for format, but the value added beyond the schema is minimal.
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 core sentence says exactly what is done: 'Fetch one page of the accounts followed by an X/Twitter account', with the specific data fields and the account's own list one-page scoping. The reference to xcrap_get_user as an alternative helps distinguish it from profile lookup. The only issue is the later example 'who follows @x' colloquially points to followers, but the core purpose is still unambiguous.
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?
It gives concrete example queries and correctly suggests xcrap_get_user when you need the account's own profile/follower count. However, it never mentions the sibling xcrap_get_followers, and while 'who follows @x' in the description actually points toward the follower direction rather than the following direction. This leaves an agent without explicit guidance to choose between this tool and xcr_transform_get_followers, which is the main sibling confusable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
xcrap_get_repliesGet the replies to an X postARead-only
Fetch the replies under an X/Twitter post, most liked first or newest first, with the post itself on top.
This is how you answer "what are people saying about this post", "what did the replies think" or "find the strongest pushback on this". Only direct replies come back — a reply to a reply belongs to its own conversation.
When to use this instead of the alternatives:
Use xcrap_get_tweet if you only need the post.
Use xcrap_get_thread for the author's own follow-up posts; replies by other people are not a thread.
Args:
url (string, required): the post's URL or bare numeric id.
sort ('top' | 'recent'): 'top' (default) for the most liked first, 'recent' for the newest first.
format ('markdown' | 'json'): default 'markdown'.
Returns markdown: a "Replies to" heading, the post, then each reply with its author, timestamp, text and metrics. Returns json: { tweet_id, tweet_url, sort, count, tweet{...}, replies[ ] }.
There is no paging: this is the single page X serves for the post, up to about a hundred replies. Costs 20 calls/minute. A 404 means the post is deleted, private or never existed.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | The post whose replies to read: URL or bare numeric id. | |
| sort | No | 'top' (default) for the most liked replies first, 'recent' for the newest first. | top |
| format | No | Output format. 'markdown' (default) is compact, human-readable and costs roughly a tenth of the tokens of the same data as JSON — prefer it for reading and summarising. Use 'json' only when you need exact field access: numeric ids, media URLs, per-metric values, or provenance metadata. | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/destructive annotations, the description discloses meaningful runtime behavior: there is no paging, results are limited to roughly one hundred replies from the single page X serves, only direct replies are included, a 404 indicates the post is deleted/private/never existed, and there is a 20 calls/minute rate limit. All of this adds context the annotations cannot provide.
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 description is longer than strictly minimal but is well-organized: purpose, usage cues, sibling routing, args, return shapes, and constraints each have a clear section. The Args block partly repeats schema content, but the extra behavioral and return information justifies the length.
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?
Despite having no output schema, the description fully compensates by documenting return formats, limits, error semantics, sorting behavior, and rate limiting. Combined with the sibling guidance and parameter coverage, an agent has everything it needs to select and invoke this tool correctly.
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?
The input schema already covers all three parameters at 100%, so the baseline is 3. The description adds value for the format parameter by specifying exact markdown and JSON return structures, including the JSON field shape and token-cost rationale, which helps the agent choose and process the output correctly.
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 the replies under an X/Twitter post, most liked first or newest first, with the post itself on top.' It also scopes the behavior precisely by noting only direct replies are returned and sets the tool apart from siblings like xcrap_get_tweet and xcrap_get_thread.
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?
Explicitly gives when-to-use examples ('what are people saying about this post', 'find the strongest pushback on this') and names alternatives: use xcrap_get_tweet for just the post and xcrap_get_thread for the author's own follow-ups, adding that replies by other people are not a thread. This is model guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
xcrap_get_threadUnroll an X threadARead-onlyIdempotent
Unroll a whole X/Twitter thread from any post in it, returning every post by the original author in order as one readable document.
This is the tool for "read this thread and summarise it". Give it the link the user pasted — first post, last post or anywhere in the middle — and it reconstructs the run. Replies by other people are excluded: a thread is one author's chain, not the surrounding conversation.
When to use this instead of the alternatives:
Use this when the link is part of a series of connected posts, or when a single post ends mid-thought.
Use xcrap_get_tweet if you only want the one post the URL points at (a thread costs more: 20 calls/minute).
Use xcrap_get_user_tweets to read an account's recent posts generally, rather than one connected chain.
Args:
url (string, required): any post in the thread, as a URL or numeric id.
max_tweets (number, 1-100): how many posts to unroll, default 25. Lower it if a response comes back truncated.
format ('markdown' | 'json'): default 'markdown'.
Returns (markdown): the author heading, then every post in order with its timestamp, text and metrics. Returns (json): { root_id, author{...}, count, truncated, tweets[ ] }. The 'truncated' flag is true when the thread is longer than max_tweets.
Note: threads are reconstructed from X's public data, so a very old thread may come back partial — 'truncated' and the post count tell you when that happened.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Any post in the thread, as a URL or numeric id. | |
| format | No | Output format. 'markdown' (default) is compact, human-readable and costs roughly a tenth of the tokens of the same data as JSON — prefer it for reading and summarising. Use 'json' only when you need exact field access: numeric ids, media URLs, per-metric values, or provenance metadata. | markdown |
| max_tweets | No | Maximum posts to unroll, 1-100 (default 25). Each post costs roughly 200-400 characters of context; lower this if the result is truncated. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, openWorldHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds valuable behavioral context: 'Replies by other people are excluded', the cost of 20 calls/minute, and the caveat about old threads possibly being partial with the 'truncated' flag. It doesn't mention pagination or exact HTTP details, but it goes beyond annotations with meaningful behavioral notes.
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 description is well-structured with a clear first paragraph on purpose, followed by a 'When to use' section, then Args and Returns outlines. It is longer than a minimal description but every part earns its place: the alternative routing, the cost note, and the return format details are all useful. The only minor redundancy is restating schema info like defaults, but it adds value with examples (e.g., 'first post, last post or anywhere in the middle').
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?
Given no output schema, the description compensates by detailing the return formats: markdown has author heading and posts with timestamp/text/metrics; json has root_id, author, count, truncated, and tweets. The 'truncated' flag is explained. Combined with annotations for safety and the comprehensive parameter docs, the description is sufficient for an agent to invoke the tool correctly in typical thread-summarisation scenarios.
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 100%, so the parameters are already described well. The description adds extra value by explaining the purpose: 'url' can be any post in the thread, 'max_tweets' should be lowered if the response comes back truncated, and 'format' has a token-cost comparison that helps the agent decide. This exceeds the schema details without contradicting them, so above the baseline of 3.
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 description clearly states the tool unrolls an X/Twitter thread from any post in it, returning all posts by the original author in order as a readable document. It explicitly differentiates from siblings by noting it reconstructs a chain, not a single tweet or an account's general tweets, so an agent can easily select it.
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 description provides explicit 'When to use' guidance, including conditions like 'when the link is part of a series of connected posts' and 'when a single post ends mid-thought'. It also clearly states when NOT to use it: use xcrap_get_tweet for a single post, and xcrap_get_user_tweets for general recent posts, with a rationale about cost (20 calls/minute). This is exemplary routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
xcrap_get_trendsGet X trending topicsARead-only
Fetch what is trending on X/Twitter right now: the topic or hashtag, its context line where X provides one, and its post volume.
Use this for "what is trending", "what is everyone talking about on X" or as a starting point before searching for posts on a topic. The list is live and refreshed every few minutes, so the same call twice an hour apart will legitimately return different results.
Args:
count (number, 1-50): how many trends, default 20.
Returns markdown: a table of rank, topic, context and post count.
Note: trends are global, not localised to a country or city. If the list comes back empty, X was not serving trends at that moment — retry in a minute rather than concluding nothing is trending.
| Name | Required | Description | Default |
|---|---|---|---|
| count | No | Number of trending topics to return, 1-50 (default 20). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint and openWorldHint annotations, the description discloses that the list is live and refreshed every few minutes, so repeated calls may legitimately return different results. It also explains the empty-list case as a transient X condition and advises retrying, which is valuable behavioral context.
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 description is well organized and front-loaded: purpose, usage guidance, live-data caveat, parameter, return format, and a practical empty-result note. Each sentence adds distinct value without unnecessary jargon or repetition.
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 no output schema, the description provides the return format (markdown table of rank, topic, context, post count). It covers the only parameter, the global scope, the live-refresh behavior, and how to handle an empty response, so an agent has everything needed to call and interpret the tool correctly.
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 100%: the count parameter's range and default are already fully documented in the schema. The description repeats the default and range but adds little beyond that, so the baseline 3 is appropriate.
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 description opens with a specific verb and resource: 'Fetch what is trending on X/Twitter right now,' and names the returned content (topic/hashtag, context line, post volume). This clearly distinguishes it from sibling tools that get tweets, users, replies, or search results.
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 description explicitly states when to use it: for 'what is trending' queries and as a starting point before searching for posts on a topic. It does not name an alternative tool as a direct contrast, but the intended usage is clear and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
xcrap_get_tweetGet an X postARead-onlyIdempotent
Fetch one post (tweet) from X/Twitter by URL or numeric id, including its full text, author, timestamp, engagement metrics, attached media, poll, quoted post and community note.
Works without any X account, API key or login, and reads posts that x.com refuses to show logged-out visitors. Long-form posts are returned in full, not truncated at 280 characters.
When to use this instead of the alternatives:
Use this for ONE specific post. It is the cheapest tool here (60 calls/minute).
Use xcrap_get_thread if the post is the start or middle of a multi-post thread and you want the whole thread unrolled.
Use xcrap_bulk for several posts at once — it is one call instead of N and has a far larger effective budget.
Use xcrap_list_media if you only need the image or video files attached to the post.
Args:
url (string, required): post URL or bare numeric id, e.g. "https://x.com/jack/status/20", "https://twitter.com/jack/status/20" or "20".
format ('markdown' | 'json'): default 'markdown'.
Returns (markdown): a heading with the author's name and handle, the timestamp and permalink, the post text, and a line of metrics (likes, reposts, replies, quotes, bookmarks, views). Returns (json): { id, url, text, lang, created_at, created_timestamp, author{...}, metrics{likes,retweets,replies,quotes,bookmarks,views}, media[], poll, quote, replying_to, replying_to_status, community_note, possibly_sensitive, is_note_tweet, entities[], client }.
Errors: 404 means the post is deleted, private or never existed and retrying will not help; 451 means the author opted out of XCrap.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Post URL or bare numeric id. Accepts x.com, twitter.com and mirror hosts, e.g. "https://x.com/jack/status/20" or "20". | |
| format | No | Output format. 'markdown' (default) is compact, human-readable and costs roughly a tenth of the tokens of the same data as JSON — prefer it for reading and summarising. Use 'json' only when you need exact field access: numeric ids, media URLs, per-metric values, or provenance metadata. | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
While annotations already declare readOnlyHint=true and idempotentHint=true, the description adds significant behavioral context: it works without authentication, can read posts that x.com hides from logged-out visitors, and returns long-form posts without truncation. It also discloses the output structure for both markdown and JSON, plus error semantics. There is no contradiction with the annotations; the description enriches them.
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 description is well-organized: it opens with a precise one-sentence purpose, then adds capability details, a targeted 'When to use' block, a clear Args list, a Returns section covering both output formats, and a compact Errors explanation. Despite covering many points, every sentence is useful and the structure makes it easy to scan. No redundancy or filler.
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 read-only tool with no output schema, the description fully compensates: it specifies the return fields for both markdown and JSON, explains the error semantics (404 and 451), and provides throttling information (60 calls/min). It also covers the two parameters thoroughly. An agent has everything needed to call the tool correctly and interpret its response without external documentation.
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?
The input schema already documents both parameters (url and format) at 100% coverage. The description goes further by providing concrete examples for url (full URL, twitter URL, bare id) and by explaining the trade-offs of format: markdown costs a tenth of the tokens and is preferred for reading, while JSON is for exact field access. This adds practical meaning beyond the schema's enum and default.
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 description clearly states the action ('Fetch one post (tweet) from X/Twitter by URL or numeric id') and enumerates the exact content returned (full text, author, timestamp, engagement metrics, etc.). It also distinguishes itself from sibling tools by explicitly naming xcrap_get_thread, xcrap_bulk, and xcrap_list_media with their different scopes, so an agent can immediately tell when this tool is the right one.
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 description contains a dedicated 'When to use this instead of the alternatives' section that lists concrete conditions for every relevant sibling: use for one specific post (cheapest at 60 calls/min), use xcrap_get_thread for unrolling a thread, use xcrap_bulk for multiple posts, and use xcrap_list_media for only media files. It also explains error codes (404 and 451) to prevent futile retries, which is actionable guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
xcrap_get_userGet an X profileARead-onlyIdempotent
Fetch a public X/Twitter profile by handle: display name, bio, location, website, join date, verification status, avatar and banner URLs, and follower/following/post counts.
Use this to answer "who is @x", to check whether an account exists, or to get follower counts. It returns the profile only — not the account's posts.
When to use this instead of the alternatives:
Use xcrap_get_user_tweets to read what the account has actually posted.
Use xcrap_get_tweet if you have a link to a specific post rather than an account.
Args:
handle (string, required): "jack", "@jack" or "https://x.com/jack". Handles are 1-15 letters, digits or underscores; a display name will not work.
format ('markdown' | 'json'): default 'markdown'.
Returns (markdown): name and handle heading, bio, and a table of followers, following, posts, media count, join date, verification and website. Returns (json): { id, screen_name, name, url, description, location, website, avatar_url, banner_url, joined, verified, verified_type, protected, metrics{posts,followers,following,likes,media} }.
Errors: 404 means no such account, or it is suspended or private.
| Name | Required | Description | Default |
|---|---|---|---|
| format | No | Output format. 'markdown' (default) is compact, human-readable and costs roughly a tenth of the tokens of the same data as JSON — prefer it for reading and summarising. Use 'json' only when you need exact field access: numeric ids, media URLs, per-metric values, or provenance metadata. | markdown |
| handle | Yes | X handle, @handle or profile URL, e.g. "jack", "@jack", "https://x.com/jack". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnlyHint, openWorldHint, idempotentHint, destructiveHint, so the description does not need to reintroduce those. It adds valuable behavioral context beyond the annotations: the tool returns only public profile data, its 404 error maps to absent/suspended/private accounts, and it clarifies that the standalone return is not posts. This is genuinely useful, though it does not address rate limits or auth requirements, so a 4 is appropriate rather than 5.
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 description is front-loaded with the one-line definition, then provides pragmatic 'Use this to' bullets, alternative routing, and structured sections for parameters, return format, and errors. The repetition of the field list in the intro and in the Returns section is intentional to give both a quick overview and explicit per-format details. It is long, but every section earns its place by answering the likely questions an agent has when selecting and invoking this 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?
With only two parameters and no output schema, the description fully compensates by explaining the return shape for both markdown and json formats (listing all fields and key names), error semantics, and input variations. It also distinguishes this tool from all relevant siblings and states exclusions. An agent has everything needed to call this tool correctly without inspecting nested schemas or additional documentation.
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 100% and both parameters are well-described in the schema. The description still adds meaning beyond the schema: handle accepts 'jack', '@jack', or full URL, and warns that display names won't work while noting handles are 1-15 letters/digits/underscores. For format, it reinforces the token-cost distinction between markdown and json. This goes beyond simply repeating the schema, but much of the ground is already covered, justifying a 4.
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 description uses a specific verb-resource pair ('Fetch a public X/Twitter profile by handle') and enumerates exactly what fields are returned (display name, bio, location, website, join date, verification status, avatar and banner URLs, counts). It differentiates itself from siblings by explicitly stating 'It returns the profile only — not the account's posts', making its scope unmistakable.
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 description gives direct use cases: 'Use this to answer "who is @x", to check whether an account exists, or to get follower counts.' It goes further to 'When to use this instead of the alternatives' and names both xcrap_get_user_tweets and xcrap_get_tweet with conditions for each. It also excludes the wrong use case: 'It returns the profile only — not the account's posts.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
xcrap_get_user_historyExport an X account's postsARead-onlyIdempotent
Fetch many of an account's posts in one call — walking its timeline page by page — optionally limited to a date window.
This is for "everything @x posted in March", "their last 200 posts" or "summarise what they said about Y this year". It replaces paging xcrap_get_user_tweets yourself, and it counts as one call against its budget however many pages it walks.
When to use this instead of the alternatives:
Use xcrap_get_user_tweets for a quick look at the latest posts.
Use xcrap_get_thread for one connected chain of posts.
Args:
handle (string, required): "jack", "@jack" or a profile URL.
max_posts (number, 1-200): stop after this many posts, default 50. The API allows up to 1,000, but a result that large will not fit in a context window; narrow the dates instead.
since (string): oldest post to include, as a date such as "2025-01-01".
until (string): newest post to include, as a date.
include_replies (boolean): default false. Set true to include the account's replies to other people.
Returns markdown: a "Post history" heading with the count and the window, then every post with its timestamp, permalink, text and metrics.
Costs 5 calls per 5 minutes — it is the most expensive tool here, so choose the window before calling rather than calling repeatedly. It takes about a second per twenty posts, and the further back a window sits, the patchier X's timeline is — an old window can legitimately come back empty.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Oldest post to include, as a date: "2025-01-01" or an ISO timestamp. | |
| until | No | Newest post to include, as a date: "2025-03-31" or an ISO timestamp. | |
| handle | Yes | X handle, @handle or profile URL whose posts to export. | |
| max_posts | No | Stop after this many posts, 1-200 (default 50). Narrow since/until rather than raising this. | |
| include_replies | No | Include the account's replies to other people (default false). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and openWorldHint, but the description adds significant behavioral context: it counts as one call against budget regardless of pages walked, costs 5 calls per 5 minutes (the most expensive), performance (~1 sec per 20 posts), and the risk of empty results for old windows due to X's timeline patchiness. It also discloses the markdown return format, which is not in an output schema. No contradiction with annotations.
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 description is well-structured with clear sections (purpose, when-to-use, args, returns, cost) and front-loads the core purpose. It is slightly verbose—particularly the cost and performance details—but every sentence adds operational value. No fluff, though a few sentences could be trimmed without loss.
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 tool that walks pages, has a date window, and a cost budget, the description covers everything an agent needs: purpose, usage scenarios, argument semantics, return format, cost, performance, and data-completeness caveats. No output schema exists, so the description appropriately explains the markdown structure. There are no missing critical details.
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 100%, so the baseline is 3. The description adds value beyond the schema: it explains the context-window limitation for max_posts ('The API allows up to 1,000, but a result that large will not fit in a context window; narrow the dates instead') and reinforces the recommended approach of narrowing dates rather than raising max_posts. It also clarifies handle accepts '@jack' or profile URLs. This extra guidance pushes it above the baseline.
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 description opens with a specific verb and resource ('Fetch many of an account's posts in one call — walking its timeline page by page'), and immediately distinguishes itself from siblings by explaining it replaces manual paging of xcrap_get_user_tweets. It names the alternatives (xcrap_get_user_tweets, xcrap_get_thread) with their appropriate use cases, so an agent can disambiguate without inspecting other schemas.
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?
Explicit when-to-use examples are given ('everything @x posted in March', 'their last 200 posts') alongside explicit alternatives: 'Use xcrap_get_user_tweets for a quick look at the latest posts' and 'Use xcrap_get_thread for one connected chain of posts.' This leaves no ambiguity about when to select this tool over its siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
xcrap_get_user_tweetsGet an X account timelineARead-onlyIdempotent
Fetch a page of an account's posts, newest first, with text, timestamps and metrics for each.
This is how you answer "what has @x been posting about", "find their recent posts about Y" or "what did they say this week". Paging is cursor-based because a timeline moves while you read it: pass the next_cursor from the previous call to get the next page.
When to use this instead of the alternatives:
Use xcrap_get_user for the profile and follower counts instead of the posts.
Use xcrap_get_thread when the posts you want are one connected chain rather than a general feed.
Args:
handle (string, required): "jack", "@jack" or a profile URL.
count (number, 1-100): posts per page, default 20. Above ~40 the result is likely to be truncated.
cursor (string): the next_cursor from a previous call, to fetch the following page. Omit for the first page. Do not invent one.
exclude_replies (boolean): default true — the account's own posts only. Set false to include its replies to other people.
media_only (boolean): default false. Set true for only posts carrying images or video.
Returns markdown: a "Posts by @handle" heading, the post count, then each post with its timestamp, permalink, text and metrics. To page further, call xcrap_get_user_tweets again with the cursor returned by XCrap.
Costs 20 calls/minute — one call returning 50 posts is far cheaper than 50 calls to xcrap_get_tweet.
| Name | Required | Description | Default |
|---|---|---|---|
| count | No | Posts to return, 1-100 (default 20). Use 10-25 for reading; higher values risk truncation. | |
| cursor | No | Pagination cursor from a previous call. Omit for the first page; never construct one by hand. | |
| handle | Yes | X handle, @handle or profile URL whose timeline to read. | |
| media_only | No | Return only posts with attached images or video (default false). | |
| exclude_replies | No | Exclude the account's replies to other people (default true). Set false to include them. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only/idempotent behavior, and the description adds substantial behavioral context beyond that: cursor-based paging justified by a moving timeline, truncation risk above ~40 posts, the markdown return format, and a 20 calls/minute rate limit with cost comparison to xcrap_get_tweet. No contradiction with annotations.
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 description is front-loaded with the core purpose, then organized into crisp sections for paging rationale, alternative selection, parameter semantics, return format, and cost. Every sentence contributes useful decision or invocation information without fluff.
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?
Despite having no output schema, the description explains the return value in detail ('a 'Posts by @handle' heading, the post count, then each post with its timestamp, permalink, text and metrics'), covers all five parameters, paging, rate limits, and sibling routing. An agent has everything needed to select and call this tool correctly.
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 100%, but the description still adds material meaning: handle accepts 'jack', '@jack' or a profile URL; count has a practical truncation threshold; cursor must come from a previous call and must not be invented; exclude_replies default behavior and media_only purpose are clarified. This goes well beyond the baseline schema descriptions.
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 description opens with a specific verb and resource: 'Fetch a page of an account's posts, newest first, with text, timestamps and metrics for each.' It clearly distinguishes itself from siblings by naming xcrap_get_user for profile data and xcrap_get_thread for connected chains, leaving no ambiguity about what this tool does.
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 guidance is explicit and actionable: it gives concrete question patterns like 'what has @x been posting about' and states alternatives with when to choose them ('Use xcrap_get_user for the profile and follower counts instead of the posts'). It also explains paging behavior and when to pass a cursor.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
xcrap_list_mediaList media attached to an X postARead-onlyIdempotent
List every downloadable file attached to a post — photos, videos and GIFs — with type, dimensions, duration, alt text, every available quality variant, and a direct download URL for each.
Use this when the user wants the image or the video from a post rather than its text: "download the video from this tweet", "what images are in this post", "get me the alt text". The download URLs it returns stream the original file straight from X and can be handed to the user or fetched directly.
When to use this instead of the alternatives:
Use xcrap_get_tweet if you want the post's text and only need to know whether media exists.
Use this when you need the actual file URLs, resolutions or alt text.
Args:
url (string, required): post URL or numeric id.
Returns JSON (media metadata is field-level data, so this tool does not offer a markdown mode): { tweet_id, tweet_url, author, count, media: [ { id, type: "photo"|"video"|"gif", url, thumbnail_url, width, height, duration, format, alt_text, variants[ {url, container, bitrate} ], index, download_url } ] }
A post with no attachments returns count: 0 and an empty media array — that is a successful answer, not an error.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Post URL or bare numeric id whose attachments to list. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false, idempotentHint=true. The description adds valuable context beyond annotations: it explains that download URLs stream original files directly from X, that the tool returns JSON only (no markdown mode), and that an empty media array with count 0 is a successful response, not an error. This gives the agent clear expectations about output and edge cases. It does not mention error conditions or rate limits, but annotations cover the safety profile, making a 4 appropriate.
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 description is longer than strictly necessary but well-structured: it opens with the core purpose, then usage guidance, then argument list, then return format. The front-loading is effective, and each section earns its place. While it could be trimmed slightly, it is organized and easy to scan, with no irrelevant content.
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?
The tool is simple (one parameter, no output schema), and the description covers everything needed: the exact return JSON structure, the behavior for empty posts, and the distinction from the sibling tool. The agent has all information required to correctly invoke this tool and interpret results. No critical information is missing, making it fully complete for this context.
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?
The single parameter 'url' is fully described in the schema ('Post URL or bare numeric id whose attachments to list') and reiterated in the description. Since schema coverage is 100%, the description does not need to add much; it repeats the same information without adding new semantic meaning. The baseline of 3 is correct when the schema already documents the parameter fully.
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 description clearly states a specific verb and resource: it lists all downloadable media (photos, videos, GIFs) attached to a post, with detailed attributes. It explicitly differentiates from sibling xcrap_get_tweet by noting that this tool returns actual file URLs and alt text, whereas the sibling only indicates whether media exists. The purpose is unambiguous and leaves no doubt about the tool's function.
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 description provides explicit when-to-use guidance with concrete examples like 'download the video from this tweet' and 'what images are in this post'. It names the alternative xcrap_get_tweet and gives a clear condition for choosing it: use xcrap_get_tweet if only the post's text or media existence is needed, otherwise use this tool. This is textbook usage guidance with no ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
xcrap_searchSearch X postsARead-only
Full-text search over X/Twitter posts, with the same operators X's own search understands.
This is how you answer "what are people saying about Y", "find posts from @x about Z", "any recent posts linking to this site" or "what did @x post about the launch last week". The query is passed to X as-is, so operators work: from:nasa, to:jack, "exact phrase", -exclude, lang:en, filter:links, min_faves:100.
When to use this instead of the alternatives:
Use xcrap_get_user_tweets or xcrap_get_user_history to read one account's posts without a topic.
Use xcrap_get_trends for what is trending in general, with no query.
Use xcrap_get_replies for the conversation under one specific post.
Args:
q (string, required): the search query, operators included.
feed ('latest' | 'top' | 'photos' | 'videos'): 'latest' (default) for newest first, 'top' for X's most relevant, or only posts with photos or videos.
since (string): oldest post to match, as a date such as "2025-01-01".
until (string): newest post to match, as a date.
cursor (string): the next_cursor from a previous call, for the next page. Omit for the first page. Do not invent one.
format ('markdown' | 'json'): default 'markdown'.
Returns markdown: a "Search:" heading with the result count and feed, then each post with its author, timestamp, permalink, text and metrics, and a "Next page" cursor line when there is more. Returns json: { query, feed, since, until, count, next_cursor, tweets[ ] }.
Costs 15 calls per 15 minutes — the tightest budget here. Write one precise query with operators instead of several broad ones. A 503 means search capacity is used up for now; wait for the time it gives.
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | The search query, including any X search operators, e.g. "from:nasa mars". | |
| feed | No | 'latest' (default) for newest first, 'top' for most relevant, 'photos' or 'videos' for media posts only. | latest |
| since | No | Oldest post to match, as a date: "2025-01-01" or an ISO timestamp. | |
| until | No | Newest post to match, as a date: "2025-03-31" or an ISO timestamp. | |
| cursor | No | Pagination cursor from a previous call. Omit for the first page; never construct one by hand. | |
| format | No | Output format. 'markdown' (default) is compact, human-readable and costs roughly a tenth of the tokens of the same data as JSON — prefer it for reading and summarising. Use 'json' only when you need exact field access: numeric ids, media URLs, per-metric values, or provenance metadata. | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the tool is safe to call. The description adds substantial behavioral context beyond that: it states that the query is passed to X as-is (operators work), explains the cost ('Costs 15 calls per 15 minutes'), describes the error handling ('A 503 means search capacity is used up for now; wait for the time it gives'), and details the return format for both markdown and JSON, including pagination via 'next_cursor'. This is comprehensive behavioral disclosure that goes well beyond the annotations.
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 description is well-structured and front-loaded: a concise one-liner about the tool's core function, followed by usage examples, then explicit sibling differentiation, then parameter details, then return format, and finally rate-limit/error info. Every section earns its place—no fluff, no repetition of schema content verbatim. It's long but efficient, with clear headers that make it scannable for an agent.
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 tool with search operators, pagination, rate limits, and multiple output formats, this description covers all necessary context: what the tool does, when to use it, how each parameter behaves (including defaults), what the return structure looks like for both markdown and JSON, the rate limit, and error handling. Since there is no output schema, the description must explain the return values, which it does thoroughly. No critical information is missing for an agent to call the tool correctly.
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?
The input schema covers 100% of parameters with descriptions, so the baseline is 3. However, the tool description adds significant extra semantic value: it explains the operator syntax in the description (from:nasa, etc.), clarifies the 'cursor' parameter ('Do not invent one'), and expands on the 'format' parameter with token-cost guidance ('prefer it for reading and summarising'). These additions go beyond the schema's descriptions, making the parameter semantics richer and more actionable.
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 description opens with a clear, specific statement: 'Full-text search over X/Twitter posts, with the same operators X's own search understands.' It immediately conveys the verb (search), the resource (X/Twitter posts), and the scope (full-text with operators). It further differentiates from siblings by naming alternatives (xcrap_get_user_tweets, xcrap_get_trends, etc.) and explaining when to use each. This is unambiguous and distinguishes it from the sibling tools.
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 description includes an explicit 'When to use this instead of the alternatives:' section that lists specific sibling tools and the conditions for choosing this tool over them. For example, 'Use xcrap_get_user_tweets or xcrap_get_user_history to read one account's posts without a topic.' This leaves no ambiguity about when to invoke this tool versus its alternatives.
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.
12 tool updates
v1.1.0- First observed
xcrap_bulk - First observed
xcrap_get_followers - First observed
xcrap_get_following - First observed
xcrap_get_replies - First observed
xcrap_get_thread - First observed
xcrap_get_trends - First observed
xcrap_get_tweet - First observed
xcrap_get_user - First observed
xcrap_get_user_history - First observed
xcrap_get_user_tweets - First observed
xcrap_list_media - First observed
xcrap_search
TDQS
Scored across 12 tools
Every tool targets a distinct retrieval mode: single post, bulk, thread, replies, user timeline/history, profile, followers/following, search, trends, and media. The 'when to use this instead of the alternatives' notes explicitly resolve the few overlapping surfaces, so an agent should not misselect.
Nine tools follow the xcrap_get_<resource> pattern and all are lowercase snake_case with the xcrap_ prefix. The exceptions are xcrap_search, xcrap_bulk, and xcrap_list_media, which use bare verbs or list_ instead of get_. Overall the pattern is predictable, just slightly imperfect.
12 tools is squarely in the well-scoped range for a read-only X/Twitter API. Each tool covers a distinct workflow and none feel like filler; the count supports both quick single-post lookups and bulk/history jobs.
For its stated purpose of reading X/Twitter public data, the surface is remarkably complete: posts (single, bulk, thread, replies), profiles, timelines, history, followers/following, search, trends, and media. There are no dead ends, and paging/error behavior is described consistently. Optional read surfaces like likes or list timelines are absent but are outside the apparent core scope.
Maintenance
Related MCP Connectors
X / Twitter public post, comment, reply, user, and search tools.
X (Twitter) profiles, tweets and single-tweet lookup by handle or URL. No login. Pay per result.
Twitter/X read-only MCP server — 12 tools: search, users, tweets, followers, timelines, trends.
X (formerly Twitter) posts, profiles, and search for AI agents. Free key, self-minted, no signup.
Related MCP Servers
- AlicenseAqualityAmaintenanceReal-time X (Twitter) data platform with 2 MCP tools covering 120+ REST API endpoints. Search tweets, look up users, get timelines, extract followers/likes/retweets in bulk, monitor accounts, run giveaway draws, and perform write actions (tweet, like, retweet, follow, DM). OAuth 2.1 authentication with PKCE.2194 npm197MIT
- AlicenseAqualityBmaintenanceEnables reading public X (Twitter) content like profiles, tweets, and search results via a stealth browser, without official API costs.11MIT
- AlicenseCqualityAmaintenanceEnables AI agents to search, read user profiles, timelines, media, follow threads, track trends, and manage accounts on X/Twitter via GraphQL, without browser automation or paid API keys.10010MIT
- AlicenseNot gradedqualityCmaintenanceConverts X (Twitter) posts into JSON, PDF, PNG, Markdown, or Slack/Discord messages using public endpoints, no API key or login required.MIT