MCP vs CLI for AI agents: token cost, auth and reliability, measured on Twitter (X) data

This page is the decision between three ways of giving an agent access to an API: an MCP server, a command-line tool, or a skill that tells the agent how to use one of those. Our llms.txt guide already compares llms.txt, SKILL.md and MCP as documentation formats, and our MCP server explainer covers how the protocol works; here we measure the trade-off builders actually argue about, MCP vs CLI, in tokens, auth steps and failure modes, and only touch skills where they change the answer.
The running example is X (Twitter) data because it is a hard case: one page of 20 posts is a large JSON object, every post carries its author's full profile, and X offers both an official CLI (xurl) and an official MCP server. We captured real tool lists from three MCP servers, the help text of xurl 1.3.4 and two published SKILL.md files, then pulled 806 posts across 45 API pages and counted what each route would put into the model's context.
Short version: the protocol is rarely the expensive part. Huge auto-generated tool lists and untrimmed results are. Pick the route that lets you control both.
MCP vs CLI: the decision in one table
Both routes end in the same HTTP request. The difference is who describes the tool to the model, who holds the credentials, and who decides what part of the response the model reads. The table is our recommendation from the measurements below, not a vendor rule.
The rule underneath the table. If you can put a filter between the API and the model, the CLI route wins on tokens almost every time. If you cannot (no shell, or a server you do not control), pick the MCP server with the smallest tool list and the leanest results, and use your host's limits and tool search to contain the rest.
Up-front cost: what each route loads before the first call
An MCP client asks the server for tools/list and passes each tool's name, description and JSON Schema to the model, so the definitions sit in context whether or not a tool is used. A CLI costs nothing until the agent runs --help or reads instructions. We captured each tool list from the server itself and counted tokens with tiktoken's o200k_base encoding; Claude and Grok use their own tokenizers, so read the numbers as a comparison between routes rather than an exact bill for every model.
Generated servers are the outlier, not MCP itself. xmcp builds one tool per operation in X's OpenAPI spec (streaming and webhook operations excluded), which gave 227 tools when we ran its own loading code; its README still lists 119, so the spec has grown since the list was written. That is about 300 tokens per tool, and the heaviest are write tools such as articleCreateDraft (1,536 tokens) and createPosts (1,184). Every one of the 227 also carries an outputSchema, 5,081,484 bytes of JSON in total; the MCP spec makes outputSchema optional, and whether a host shows it to the model varies, so we left it out of the token count.
Hand-written servers look like a CLI. The twitterapi.io server's 12 read tools cost 2,025 tokens, 169 per tool, of which 725 are descriptions. The heaviest is search_tweets at 267 tokens, because its description teaches the search operators. That is within a factor of three of reading xurl --help, and an agent using a CLI usually reads the help for the subcommand too.
Allowlists and tool search. The xmcp README offers X_API_TOOL_ALLOWLIST; with its example (getUsersByUsername,createPosts,searchPostsRecent) the list drops to 2,362 tokens. Claude Code goes further on the host side: its docs say tool search, on by default, defers tool definitions until Claude needs them, so only tool names and server instructions load at session start. Hosts without tool search pay the full list on every turn.

Per-call cost: the result, not the protocol, fills the context
The up-front list is paid once per session; results are paid on every call. We took 45 API pages from X (36 search pages and 9 timeline pages from @XDevelopers, @AnthropicAI and @OpenAIDevs, 806 posts) and counted each page three ways: as the twitterapi.io MCP server returns it (the full response through JSON.stringify(result, null, 2)), as compact JSON the way curl prints it, and after a jq-style trim to 8 fields per post (id, createdAt, text, author.userName and four counts).
Whitespace alone is 28.8%. Pretty-printing adds indentation and line breaks the model does not need; compact JSON of the same page was 28.8% fewer tokens. Trimming fields is the big win: 90.9% fewer tokens than the MCP result across all pages, 96.9% on timelines, where every post carries the organization's full profile, media objects and quoted posts.
Host limits kick in before the context does. Claude Code's docs say it warns when an MCP tool output exceeds 10,000 tokens, limits output to 25,000 tokens by default (MAX_MCP_OUTPUT_TOKENS changes it), and saves a successful text result longer than 50,000 characters to a file. In our sample 95.6% of untrimmed MCP results were over 25,000 tokens and every one was over 50,000 characters, so in Claude Code they would land in a file the agent then has to read. Only 2.2% of trimmed pages were over 10,000 tokens.
MCP servers can trim too. Nothing in the protocol forces raw output; a server can return only the fields a model needs, or put the full object in structuredContent for code and a short text summary for the model. The point is control: with a CLI you choose the filter per call; with MCP the server author chose it for you. Our own server returns the full response today, which is the right default for completeness and the wrong one for context.

Auth: where MCP and CLI really differ for X
Tokens get the attention, but auth decides how long setup takes and who can see the secret.
X's MCP leans on the CLI. X's MCP page explains that X's OAuth requires your own developer app, that there is no dynamic client registration, and that api.x.com/mcp does not advertise native MCP OAuth discovery; instead you run xurl mcp, a local bridge that does the PKCE login once and refreshes the token. Without a token the endpoint answers HTTP 401 with a www-authenticate: Bearer header, which is what we got when we called it bare. In other words, for X the MCP route still installs the CLI.
A CLI inherits the shell. Whatever key the shell has, the agent has, and an agent that can run curl can also run env. Keep keys in a separate environment for agent sessions, scope them as tightly as the provider allows, and prefer a per-agent key you can revoke. MCP's advantage is that the host can keep the token out of the model's view entirely and ask before each call.
Reads need no X account on the REST route. A twitterapi.io key reads public X data with no X developer app or X account; new accounts that pass the automatic bot check get up to $1 of free credits (at most 100,000 credits, no card, one per person or network, expiring after 31 days). Writes are a separate step: one /twitter/user_login_v2 login ($0.10, with a proxy you supply) returns login_cookies, and each post, like, retweet or follow through endpoints such as /twitter/create_tweet_v2 is then 60 credits ($0.0006), billed per HTTP 200 call. Those calls act as that account, so X can rate-limit, lock or suspend it; keep a human pace, and expect the session to need a re-login now and then.
Reliability and safety: what breaks on each route
CLI failure modes. The agent guesses a flag that does not exist, quotes a query wrong in the shell, or reads an error printed to stderr as data. xurl narrows this with fixed shortcuts and documented bounds: xurl search accepts 10 to 100 results and covers recent posts only, per its own help. The cure is short, exact usage text in a skill and a wrapper script with a small, stable interface, like the one in the code section below.
MCP failure modes. The server fails to start, the OAuth token expires mid-session, or the host truncates a large result. X's MCP page lists the usual ones: a browser that never opens on a headless machine (run xurl auth oauth2 --headless first) and a 401 or token refresh failed when app credentials are wrong or the refresh token was revoked. Claude Code reports a failed server connection to the model when tool search is on, so the agent can tell you instead of silently skipping the tool.
Prompt injection is the same on both. Posts on X are text written by strangers, and a tool result puts that text in the model's context whether it arrives through MCP or stdout. Trimming helps a little, because there is less text, but the real controls are separating read tools from write tools, keeping approval on for anything that changes state, and never letting a read result trigger a write without a person in the loop.
Validation. MCP tools publish a JSON Schema for their arguments, so the server can reject a bad call with a clear message before it reaches the API; the twitterapi.io server validates arguments and returns Invalid arguments for <tool> with the schema error. A CLI validates whatever its author bothered to validate.
Where a skill fits: instructions on top of either route
A skill is a folder with a SKILL.md: a name and a description loaded at startup, a body loaded when the task matches, and optional scripts. The Agent Skills specification puts the metadata at about 100 tokens and recommends keeping the body under 5,000 tokens. Measured: the twitterapi.io skill's front matter is 92 tokens and its body 2,840; X's skill at docs.x.com/skill.md is 86 and 2,554.
Skill + CLI is the low-token pattern. The skill tells the agent which command to run and which fields to keep; the CLI runs it; a jq filter or wrapper script trims the output. The agent pays roughly 92 tokens until X data is relevant, about 2,800 when it is, and about 4,000 per trimmed 20-post page instead of about 41,000.
Skill + MCP also works. A skill can tell the agent which MCP tool to prefer and how many pages to fetch. It does not shrink the tool list or the results; it only makes the calls fewer and better aimed.
The format comparison (llms.txt for docs lookup, SKILL.md for procedure, MCP for action) is on our llms.txt guide, and the full X skill next to ours is on the SKILL.md explainer, so we do not repeat them here.
The same X read three ways, and what it costs in dollars
Task: the latest posts from @XDevelopers, newest first. Each route below makes one call for one page.
Route 1, MCP. Add a server, ask in chat, approve the call. Host-side setup, no shell needed, full result returned.
Route 2, xurl. xurl posts XDevelopers -n 20 after an X developer app and OAuth login; it prints JSON to stdout, so the same trimming step applies.
Route 3, curl and jq. One line against the REST API, trimmed before the model sees it.
Tokens are one bill; the API is the other. Both MCP and CLI calls hit the same endpoint and cost the same per call.
The official figures are from the pay-per-usage rate card at docs.x.com/x-api/getting-started/pricing, read for this article; at $5 against $0.15 per 1,000 posts the official card is about 33 times higher. X also gives $20 of credits with a first eligible card and purchase and matches a first auto-recharge up to $50. On twitterapi.io the minimum is 15 credits per request, so a search that finds nothing costs $0.00015; you pay only for the data returned, and purchased credits never expire. Rate limits are 0.2 requests per second before the first payment and 20 once paid, higher on larger plans; plans are on /pricing.
# Route 1: MCP (Claude Code), the hosted twitterapi.io server
claude mcp add --transport http twitterapi-io https://mcp.twitterapi.io/mcp \
--header "Authorization: Bearer $TWITTERAPI_IO_API_KEY"
# then ask: "latest posts from @XDevelopers" and approve get_user_last_tweets
# Route 2: xurl, X's official CLI (needs an X developer app + OAuth first)
xurl auth oauth2 --app my-app
xurl posts XDevelopers -n 20 # prints JSON to stdout; pipe it through a filter before the model reads it
# Route 3: curl + jq against twitterapi.io, trimmed to 8 fields per post
curl -s "https://api.twitterapi.io/twitter/user/last_tweets?userName=XDevelopers" \
-H "X-API-Key: $TWITTERAPI_IO_API_KEY" \
| jq -c '.data.tweets[] | {id, createdAt, text, author: .author.userName,
likeCount, retweetCount, replyCount, viewCount}'What people on X argue about when they compare MCP and CLI
We collected 572 distinct posts matching MCP and CLI (a Latest search, a Top search for the exact phrases "mcp vs cli" and "cli vs mcp", and a broader Top search), from 509 distinct accounts; 555 were posted in 2026. 69.9% were in English, 12.9% in Chinese and 5.6% in Japanese. The theme counts come from keyword rules in the study's analyze.py, so they undercount non-English posts and are a rough map, not a survey.
Skills are now part of the argument. More posts mention skills than token cost, which matches the pattern above: the debate has moved from "MCP or CLI" to "which instructions sit on top".
Token posts travel further. Posts that mention tokens or context had a median of 21 likes against 8 for the rest (median across the whole sample 9.5 likes, 851.5 views).
Few posts pick a side outright. Only 7 posts matched our explicit pro-CLI phrasings and 9 our pro-MCP ones; most posts describe a setup that uses both. curl came up in 5 posts and xurl in none, so the X-specific CLI is not yet part of the general conversation.
How we collected this
Question. What does each route for giving an agent X data cost in context tokens, up front and per call, and what do posts about MCP and CLI argue about?
Tool lists. tools/list from @twitterapi_io/mcp-server 0.2.0 (npm, MIT) started locally over stdio with a dummy key; tools/list from X's public docs MCP; and the list that xdevplatform/xmcp builds from X's OpenAPI spec, reproduced in memory with its own load_openapi_spec and filter_openapi_spec functions and FastMCP 4.1.4. X's hosted api.x.com/mcp requires OAuth, so we could not list its tools; its docs give the server name as xmcp, but we did not confirm that the hosted list matches the repository's.
CLI and skills. The xurl 1.3.4 macOS binary from the GitHub release (checksum verified) for --help text, and the two SKILL.md files as served. Tokens counted with tiktoken o200k_base.
X data. 55 read requests through a rate-limited client: 46 search pages (Latest and Top, query MCP CLI -filter:retweets, plus the exact-phrase query) and 9 timeline pages from @XDevelopers, @AnthropicAI and @OpenAIDevs; 829 posts returned, collected in 2026, about $0.12 at 15 credits per post. The per-call measurement used the 45 pages with 10 or more posts (806 posts).
What it cannot show. Token counts differ by tokenizer; hosts differ in what they pass to the model (output schemas, deferred tools); the conversation sample is a slice of recent and top posts, not all posts; and keyword themes miss posts that make the same point in other words or languages.
Privacy. Aggregates only. Organization accounts are named; individual authors are not, raw search pages were not kept in the repository, and the de-identified sample holds no IDs, URLs, handles or text.
#!/usr/bin/env python3
"""xsearch: a tiny CLI an agent can call instead of an MCP tool.
Prints one compact JSON line per post with 8 fields, so a 20-post page
lands in context as about 4,000 tokens instead of about 41,000.
Usage: TWITTERAPI_IO_API_KEY=... python3 xsearch.py "from:XDevelopers" --pages 2
"""
import argparse
import json
import os
import sys
import requests
BASE = "https://api.twitterapi.io"
def trim(t):
return {
"id": t.get("id"),
"createdAt": t.get("createdAt"),
"text": t.get("text"),
"author": (t.get("author") or {}).get("userName"),
"likeCount": t.get("likeCount"),
"retweetCount": t.get("retweetCount"),
"replyCount": t.get("replyCount"),
"viewCount": t.get("viewCount"),
}
def main():
ap = argparse.ArgumentParser(description="Search X posts, print trimmed JSON lines")
ap.add_argument("query", help="X search query, e.g. 'mcp cli lang:en'")
ap.add_argument("--type", default="Latest", choices=["Latest", "Top"])
ap.add_argument("--pages", type=int, default=1, help="pages of about 20 posts")
a = ap.parse_args()
key = os.environ.get("TWITTERAPI_IO_API_KEY")
if not key:
sys.exit("set TWITTERAPI_IO_API_KEY")
params = {"query": a.query, "queryType": a.type}
for _ in range(a.pages):
r = requests.get(
f"{BASE}/twitter/tweet/advanced_search",
headers={"X-API-Key": key},
params=params,
timeout=30,
)
r.raise_for_status()
body = r.json()
for t in body.get("tweets", []):
print(json.dumps(trim(t), ensure_ascii=False))
if not body.get("has_next_page") or not body.get("next_cursor"):
break
params["cursor"] = body["next_cursor"]
if __name__ == "__main__":
main()
Questions readers ask
Is MCP or CLI better for AI agents?
Neither wins everywhere. A CLI is better when the agent has a shell and you want to trim output before the model reads it; in our measurement that cut a 20-post X read from a median 41,250 tokens to 4,069. MCP is better when there is no shell, when many users share an integration with their own OAuth accounts, or when you want the host to approve each call.
Why do people say MCP uses more tokens than a CLI?
Two reasons. Tool definitions load before the first call: the auto-generated X API server xmcp lists 227 tools in 68,198 tokens, against 747 for xurl --help. And many servers return full API responses: a pretty-printed 20-post page was 41,250 tokens. Small hand-written servers (12 tools in 2,025 tokens) and hosts with tool search shrink the first cost; only trimming shrinks the second.
Does Claude Code load every MCP tool into context?
Not by default. Claude Code's MCP docs say tool search is on by default and defers tool definitions until Claude needs them, so only tool names and server instructions load at session start. It also warns when a tool output exceeds 10,000 tokens and limits output to 25,000 tokens unless you set MAX_MCP_OUTPUT_TOKENS.
What is xurl, and is it a replacement for X's MCP server?
xurl is X's official command-line client for the X API (MIT, version 1.3.4 on GitHub). It is also the bridge X's MCP docs tell you to use: xurl mcp handles the OAuth login and passes a Bearer token to api.x.com/mcp. So for X the two are complements, and both need your own X developer app.
Where do skills (SKILL.md) fit in MCP vs CLI?
A skill is instructions, not a transport. Its name and description load at startup (92 tokens for the twitterapi.io skill), and the body loads when the task matches (2,840 tokens). It tells the agent which CLI command or MCP tool to use and how to keep results small, so it pairs with either route.
Can an MCP server return less data so it costs fewer tokens?
Yes. Nothing in the protocol requires raw output. A server can return only the fields a model needs, or put the full object in structuredContent and a short summary in the text content. If you do not control the server, an allowlist or a host-side output limit is the remaining lever.
Is calling an API through MCP more expensive in dollars than through a CLI?
No. Both make the same API request and pay the same per-call price. On twitterapi.io a full 20-post page is $0.003 ($0.15 per 1,000 posts) either way; on the official X API pay-per-usage card the same 20 post reads are $0.10 ($0.005 each). The difference between routes is tokens, not API fees.
Continue
- Model Context Protocol specification: Tools (tools/list, inputSchema, optional outputSchema, human in the loop)
- Claude Code docs: MCP (tool search, output warning at 10,000 tokens, 25,000-token default limit)
- X developer docs: MCP servers for the X API and docs (api.x.com/mcp, xurl mcp bridge)
- xdevplatform/xurl on GitHub: the official X API CLI (v1.3.4)
- xdevplatform/xmcp on GitHub: X API OpenAPI spec as MCP tools, X_API_TOOL_ALLOWLIST
- Agent Skills specification: SKILL.md format and progressive disclosure
- Twitter (X) API overview: endpoints, pricing and access
- What an MCP server is, with a live X example
- llms.txt vs SKILL.md vs MCP for API docs
- SKILL.md explained: X's skill and a Twitter API skill
- xurl, the X API CLI: install, auth and cost per read
- Build an MCP server in Python for X data
- How Twitter (X) access tokens and keys work
- TwitterAPI.io pricing and plans
- 01Twitter (X) Clients in 2026: Which Ones Still Work, by Platform
- 02How to Mass Block on Twitter (X): Tools, Block Lists and Safer Options
- 03Does Twitter (X) Delete Inactive Accounts? The Policy, the Purge, and What Actually Survives
- 04How to View a Suspended Twitter (X) Account, and What Still Survives
- 05Twitter (X) Temporary Label: What "May Impact Its Reach" Means and What to Do
- 06What Is an MCP Server? How AI Clients Talk to It, With a Live Twitter (X) Example
- 07MCP Server Workflow Automation: the 14 Best MCP Servers for Claude Code, Codex and Cursor, Twitter (X) Data Included
- 08Codex MCP: How to Add Any MCP Server to OpenAI Codex (CLI, IDE and App)
Stop reading. Start building.
Starter credits cover real testing on real data. Google sign-in, no card, no application queue.
Get an API keyAlready building with TwitterAPI.io? Publish an honest tutorial or build log about it and earn up to $200 a month in API credits.