fanfou-mcp
A Model Context Protocol server that lets an AI assistant read Fanfou (饭否) timelines, search statuses, look up users, and — with explicit confirmation — post, delete, favorite and follow.
Account check:
verify_credentialsreturns the authenticated Fanfou account.Timelines:
home_timeline,user_timeline,mentions,public_timeline— read statuses withcount(1–60),since_id,max_id,pagefilters.Search:
search_public_timelineandsearch_user_timelinefor keyword search (a b= AND,a|b= OR).Lookups:
get_status(one status by id),get_context(reply chain/conversation),get_user(profile),favorites(a user's favorited statuses).Write actions:
post_status(post/reply/repost),delete_status,favorite(create/destroy),friendship(follow/unfollow) — each requiresconfirm=trueafter your explicit approval, and is unregistered entirely whenFANFOU_MCP_READONLY=1(the HTTP default).Run anywhere: stdio for local clients (Claude Desktop, Cursor), or Streamable HTTP
/mcpfor remote/serverless hosting, including multi-user instances where each person authorizes their own Fanfou account and receives a personal bearer token (read-only).
Exposes the Fanfou (饭否) REST API as MCP tools for reading and writing a user's timeline: fetching home, user, public and mention timelines, searching public statuses and within a user's statuses, retrieving individual statuses and their reply-chain context, looking up user profiles and favorites, plus posting, deleting and reposting statuses, favoriting/unfavoriting, and following/unfollowing users (write actions require explicit confirmation).
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@fanfou-mcpshow me my home timeline"
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.
fanfou-mcp
A Model Context Protocol server for Fanfou (饭否). 让 Claude、Cursor 等 MCP 客户端直接读写你的饭否时间线。
fanfou-mcp exposes the Fanfou REST API as MCP tools so that an AI assistant can read your timeline,
search statuses, look up users and (optionally, with explicit confirmation) post, delete, favorite and follow.
It ships with two transports sharing the same tool set:
Transport | Entry point | Typical use |
stdio |
| Local MCP clients (Claude Desktop, Cursor, …) launching the server as a subprocess |
Streamable HTTP |
| Remote / serverless hosting, e.g. on Vercel — single-user (one bearer token) or multi-user (each user authorizes their own Fanfou account) |
Python ≥ 3.12, built on the official mcp Python SDK (FastMCP).
The Fanfou client itself uses only the standard library (no requests / oauthlib).
⚠️ Before you start: you need your own Fanfou app key
Fanfou has not accepted new API application registrations since 2020 (the developer program is whitelist-only). 饭否自 2020 年起不再开放新应用申请,新注册的应用无法通过审核,调用 API 会返回 401。
This project therefore does not include any consumer key. To use it you must bring:
A consumer key / secret of a Fanfou app that has already been approved (审核通过), and
An OAuth access token / secret for your account, obtained with that app (see OAuth authorization).
An app whose review status is "rejected" (已驳回) or pending will be able to complete the OAuth handshake,
but every API call (even /help/test.json) will fail with 401 参数错误!.
Related MCP server: twscrape-twitter-mcp
Tools
Read-only tools (11)
Tool | Description |
| Return the authenticated account |
| Home timeline (statuses from people you follow); |
| A user's statuses ( |
| Statuses mentioning you |
| Latest public statuses |
| Keyword search across public statuses ( |
| Keyword search within one user's statuses |
| One status by id |
| Conversation context (reply chain) of a status |
| A user's profile ( |
| A user's favorited statuses |
Write tools (4)
Tool | Description |
| Post a status; supports |
| Delete one of your own statuses |
| Favorite ( |
| Follow ( |
Safety rails for write tools:
Every write tool requires
confirm=true. Without it, nothing is sent and the tool returns an error (post_statusalso returns apreviewof the text). Tool descriptions instruct the model to only setconfirm=trueafter the user has explicitly approved the exact action in chat.Set
FANFOU_MCP_READONLY=1to not register the write tools at all. This is the default for the HTTP server (http_app.py); the stdio server defaults to0(write tools available).
Responses are trimmed to the useful fields (id, text, author, timestamps, photo URL, repost, …) to keep
the model's context small. API errors are returned as {"error": "..."} rather than raised.
Architecture
fanfou_api.py Minimal Fanfou OAuth 1.0a client (HMAC-SHA1 signing, stdlib urllib)
creds.py Credential resolution: app key from env + per-request user token; multi-user token storage
kv.py Tiny KV client: Vercel KV / Upstash Redis REST API (stdlib), or in-memory for local dev
tools.py FastMCP instance and all 15 tool definitions; READONLY switch
server.py stdio entry point -> mcp.run()
http_app.py Streamable HTTP ASGI app -> POST /mcp, GET /healthz, bearer auth,
GET /authorize, GET /callback, POST /revoke (multi-user)Helper scripts:
File | Purpose |
| Launch the stdio server via |
| Serve |
| stdio smoke test: list tools, call a few read tools ( |
| HTTP smoke test against a local or remote |
| Multi-user end-to-end test (OAuth routes, per-user tokens, revoke) |
| Local stand-in for the KV REST API, for testing |
| Issue a personal token for an existing Fanfou access token (admin / migration) |
Notes on the HTTP app:
Stateless, JSON responses (
stateless_http=True,json_response=True) and a freshStreamableHTTPSessionManagerper request, so it does not depend on ASGI lifespan — safe for serverless.creds.current_principal/creds.current_user_tokenareContextVars set per request by the auth layer. In multi-user mode they carry the calling user's Fanfou token (looked up in KV); with the admin token, or over stdio, the owner token from env is used. Tools never see bearer tokens.
Implementation notes (Fanfou quirks)
These cost real debugging time; they are documented here so you don't have to rediscover them.
OAuth 1.0a: sign
http://, requesthttps://. Requests are sent tohttps://api.fanfou.com/..., but the OAuth signature base string must use thehttp://URL. Signing the https URL fails withInvalid signature. Expected basestring is GET&http%3A%2F%2F.... 签名 base string 必须用http://,实际请求走https://。The API gateway rejects
curl/*User-Agents.api.fanfou.comanswers an nginx404for anycurl/*UA, so the client sends its ownUser-Agent. Keep this in mind when testing by hand with curl (pass-A something-else).Requests use
mode=litewhere supported to get smaller payloads.Percent-encoding follows RFC 3986 (
quote(s, safe="~")) for both the signature and the request.
Configuration
Variable | Required | Description |
| yes | Consumer key of an approved Fanfou app |
| yes | Consumer secret |
| single-user | User access token (owner account; optional in multi-user mode) |
| single-user | User access token secret |
| HTTP only | Admin / owner bearer token ( |
| multi-user (option A) | Vercel KV / Upstash Redis REST credentials. Also accepts |
| multi-user (option B) | Redis URL (Vercel Marketplace Redis injects this; |
| multi-user | Public origin used to build the OAuth callback, e.g. |
| no |
|
| no |
|
| no |
|
Optional convenience for run.sh / dev_http.sh (environment variables always win):
~/.fanfou_app— an INI-like file with sections headed# <app name>containingFANFOU_API_KEY=.../FANFOU_API_SECRET=...; select the section withFANFOU_APP_SECTION(defaultdefault).FANFOU_TOKEN_FILE(default~/.fanfou_token) — a file containingFANFOU_OAUTH_TOKEN=.../FANFOU_OAUTH_TOKEN_SECRET=...lines.
Never commit these files or a .env (both are git-ignored).
Running locally (stdio)
Requires uv.
git clone https://github.com/Anthonyeef/fanfou-mcp.git
cd fanfou-mcp
uv sync
export FANFOU_API_KEY=<consumer_key>
export FANFOU_API_SECRET=<consumer_secret>
export FANFOU_OAUTH_TOKEN=<access_token>
export FANFOU_OAUTH_TOKEN_SECRET=<access_token_secret>
uv run python test_client.py --all # smoke testMCP client configuration
Claude Desktop (claude_desktop_config.json), Cursor (~/.cursor/mcp.json) and most other clients accept:
{
"mcpServers": {
"fanfou": {
"command": "uv",
"args": ["run", "--directory", "/absolute/path/to/fanfou-mcp", "python", "server.py"],
"env": {
"FANFOU_API_KEY": "<consumer_key>",
"FANFOU_API_SECRET": "<consumer_secret>",
"FANFOU_OAUTH_TOKEN": "<access_token>",
"FANFOU_OAUTH_TOKEN_SECRET": "<access_token_secret>",
"FANFOU_MCP_READONLY": "1"
}
}
}
}Drop FANFOU_MCP_READONLY (or set it to 0) if you want the write tools. Alternatively point command
at /absolute/path/to/fanfou-mcp/run.sh and let it load credentials from local files.
Local HTTP server
export MCP_AUTH_TOKEN=$(python3 -c "import secrets; print(secrets.token_urlsafe(32))")
./dev_http.sh # serves http://127.0.0.1:8765/mcp
uv run python test_http_client.py # in another shell, same envRemote deployment (Vercel)
pyproject.toml declares the ASGI entry point for Vercel's Python runtime:
[tool.vercel]
entrypoint = "http_app:app"Create a project in your Vercel account/team. Framework preset: Python (not "Other"/null — with no preset Vercel expects functions under
/api). Root directory: this repo.Add environment variables (Production, mark as Sensitive):
FANFOU_API_KEY,FANFOU_API_SECRET,FANFOU_OAUTH_TOKEN,FANFOU_OAUTH_TOKEN_SECRET,MCP_AUTH_TOKEN(a fresh random string), and optionallyFANFOU_MCP_READONLY=1(already the HTTP default). Do not setFANFOU_MCP_ALLOW_NOAUTH.Deploy:
vercel deploy --prodfrom the repo, or connect the Git repository. Preview deployments sit behind Vercel Deployment Protection, so test against the production domain.Verify:
curl https://<your-project>.vercel.app/healthz MCP_AUTH_TOKEN=<token> uv run python test_http_client.py https://<your-project>.vercel.app/mcpConnect a client that supports remote MCP servers:
{ "mcpServers": { "fanfou": { "url": "https://<your-project>.vercel.app/mcp", "headers": { "Authorization": "Bearer <MCP_AUTH_TOKEN>" } } } }
Endpoints: POST /mcp (MCP Streamable HTTP, stateless, JSON), GET /healthz (returns
{"ok": true, "readonly": ...}). vercel.json requests the hkg1 region; Vercel may still run the
function elsewhere — the Fanfou API has been reachable from US regions as well.
Security: with the single-user model, anyone holding
MCP_AUTH_TOKENacts as your Fanfou account. Treat it like a password and rotate it if leaked. Keep the remote server read-only unless you need writes.
Hosting a multi-user instance / 托管多用户实例
One deployment can serve many people: everyone connects to the same /mcp endpoint, but each person
authorizes their own Fanfou account in the browser and gets a personal bearer token, so tools read
their own timeline. 同一个实例服务多人,每人授权自己的饭否账号、拿到自己的个人令牌。
How it works:
GET /authorize— the server requests a Fanfou request token (withoauth_callback=<public url>/callback), stores its secret in KV for 10 minutes, and redirects the browser to Fanfou's authorization page.The user logs in to Fanfou and approves the app.
GET /callback— Fanfou redirects back; the server consumes the request-token secret (one-shot), exchanges it for the user's access token, callsverify_credentials, generates a random personal token (ffm_…, 256 bits) and shows it once, together with a ready-to-paste MCP client config.POST /mcpwithAuthorization: Bearer ffm_…— the server looks the token up in KV and runs the tools with that user's Fanfou token. Unknown or revoked tokens get401.POST /revokewith the same bearer deletes the personal token.
Storage (Vercel KV / Upstash Redis, REST API):
Key | Value | TTL |
| request token secret | 10 min, deleted on use |
|
| none |
Personal tokens are never stored in clear, only their SHA-256. The KV does hold users' Fanfou access tokens, so treat the KV credentials as secrets.
Setup on Vercel: attach either a KV / Upstash store (injects KV_REST_API_URL + KV_REST_API_TOKEN)
or the official Redis Marketplace integration (injects REDIS_URL). Either one enables multi-user
mode; REST is preferred when both are set. Then set FANFOU_MCP_PUBLIC_URL, keep FANFOU_API_KEY /
FANFOU_API_SECRET (an approved app), and redeploy. MCP_AUTH_TOKEN + FANFOU_OAUTH_TOKEN[_SECRET] are
optional and keep working as an admin/owner login. See DEPLOY.md.
Things to consider before opening an instance to others:
All users share one consumer key: Fanfou rate limits apply to that app, and abuse by one user can affect everyone. Make sure your use of the key complies with Fanfou's terms.
Keep the instance read-only (
FANFOU_MCP_READONLY=1, the HTTP default).Anyone holding a personal token can read that user's Fanfou (including protected statuses they can see).
Local test without a real KV:
python dev/mock_upstash.py 8079 & # fake KV REST API
export KV_REST_API_URL=http://127.0.0.1:8079 KV_REST_API_TOKEN=dev
export FANFOU_API_KEY=... FANFOU_API_SECRET=... FANFOU_OAUTH_TOKEN=... FANFOU_OAUTH_TOKEN_SECRET=...
export MCP_AUTH_TOKEN=$(python3 -c "import secrets; print(secrets.token_urlsafe(32))")
./dev_http.sh &
uv run python test_multiuser.py # end-to-end checks
# or by hand: open http://127.0.0.1:8765/authorize in a browser, approve on Fanfou,
# then: MCP_AUTH_TOKEN=<the ffm_ token shown> uv run python test_http_client.pyConnecting as a user / 作为用户如何授权接入
If someone runs a hosted instance for you (e.g. https://<instance>):
Open
https://<instance>/authorizein your browser, log in to Fanfou and click approve. 打开授权链接,登录饭否并同意授权。You land on a page showing your personal token (
ffm_…) and a config snippet. Copy it now — it is shown only once. 令牌只显示一次,请立即保存。Add the server to your MCP client:
{ "mcpServers": { "fanfou": { "url": "https://<instance>/mcp", "headers": { "Authorization": "Bearer <your personal token>" } } } }To disconnect:
curl -X POST https://<instance>/revoke -H "Authorization: Bearer <your personal token>", and/or revoke the app's authorization in your Fanfou account settings. Lost the token? Just authorize again to get a new one.
The hosted instance is read-only: it can read your timeline, mentions, favorites and search, but cannot post, delete, favorite or follow on your behalf.
OAuth authorization (oob PIN)
Fanfou uses OAuth 1.0a. For a personal setup the simplest way to get an access token is the out-of-band (PIN) flow. 用 oob PIN 方式拿 access token:
Request token — signed (consumer key/secret only, empty token secret) request with
oauth_callback=oob:GET https://fanfou.com/oauth/request_tokenResponse:
oauth_token=<request_token>&oauth_token_secret=<request_token_secret>Authorize — open in a browser while logged in to Fanfou, and approve:
https://fanfou.com/oauth/authorize?oauth_token=<request_token>&oauth_callback=oobFanfou shows a PIN (verifier).
Access token — signed with the request token/secret and
oauth_verifier=<PIN>:GET https://fanfou.com/oauth/access_tokenResponse:
oauth_token=<access_token>&oauth_token_secret=<access_token_secret>→ use them asFANFOU_OAUTH_TOKEN/FANFOU_OAUTH_TOKEN_SECRET.
The same quirks apply: sign the http://fanfou.com/oauth/... URL while sending the request over
https, and don't use a curl/* User-Agent. A minimal standalone helper:
# oauth_pin.py — usage: python oauth_pin.py (needs FANFOU_API_KEY / FANFOU_API_SECRET in env)
import base64, hashlib, hmac, os, secrets, time, urllib.parse as up, urllib.request as ur
CK, CS = os.environ["FANFOU_API_KEY"], os.environ["FANFOU_API_SECRET"]
q = lambda s: up.quote(str(s), safe="~")
def call(path, token="", token_secret="", **extra):
p = {"oauth_consumer_key": CK, "oauth_nonce": secrets.token_hex(8), "oauth_signature_method": "HMAC-SHA1",
"oauth_timestamp": str(int(time.time())), "oauth_version": "1.0", **extra}
if token:
p["oauth_token"] = token
norm = "&".join(f"{q(k)}={q(v)}" for k, v in sorted(p.items()))
base = "&".join(["GET", q(f"http://fanfou.com{path}"), q(norm)]) # sign http://
key = f"{q(CS)}&{q(token_secret)}".encode()
p["oauth_signature"] = base64.b64encode(hmac.new(key, base.encode(), hashlib.sha1).digest()).decode()
hdr = {"Authorization": "OAuth " + ", ".join(f'{k}="{q(v)}"' for k, v in p.items()),
"User-Agent": "fanfou-mcp-oauth/0.1"}
with ur.urlopen(ur.Request(f"https://fanfou.com{path}", headers=hdr), timeout=20) as r: # send https://
return dict(up.parse_qsl(r.read().decode()))
req = call("/oauth/request_token", oauth_callback="oob")
print("Open and approve:\n https://fanfou.com/oauth/authorize?oauth_token=%s&oauth_callback=oob" % req["oauth_token"])
pin = input("PIN: ").strip()
acc = call("/oauth/access_token", req["oauth_token"], req["oauth_token_secret"], oauth_verifier=pin)
print("FANFOU_OAUTH_TOKEN=%s\nFANFOU_OAUTH_TOKEN_SECRET=%s" % (acc["oauth_token"], acc["oauth_token_secret"]))Store the printed values somewhere private (a password manager, a chmod 600 file, or your host's
secret store). You can revoke the authorization from your Fanfou account settings at any time.
Roadmap
KV/Redis-backed per-user tokens + web OAuth callback flow, enabling multi-user hosting
MCP OAuth (authorization-server metadata) so clients can connect without pasting a token
Photo upload (
/photos/upload.json), direct messages, follower/friend lists
Contributions are welcome — please open an issue or PR.
Acknowledgements
Model Context Protocol and its Python SDK
License
MIT © Anthonyeef
Available Tools
15 toolsdelete_statusA
Delete one of the user's own statuses. WRITE ACTION: only call after the user has explicitly confirmed this exact action and content in chat. Requires confirm=true.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | No | ||
| status_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does well: it labels the operation a WRITE ACTION, states the confirmation gate, and ties it to the confirm parameter. It omits irreversibility, behavior when the status does not exist or is not owned, and rate limits, which keeps it short of a 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?
Two sentences, no filler, with the action and the safety gate front-loaded before the parameter requirement. Every clause earns its place.
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 destructive two-parameter tool with no annotations and no output schema, the definition covers the essentials an agent needs to act safely: what is deleted, the ownership constraint, and the confirmation gate. Failure modes and reversibility are the only notable omissions.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It explains the semantics of confirm ('Requires confirm=true') but says nothing about status_id format or where it comes from, leaving half the parameters undocumented.
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?
Specific verb (Delete) plus resource (status) with a clear ownership scope ('one of the user's own statuses'), which separates it from get_status, post_status and favorite in the sibling list. An agent can identify the operation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit precondition for invocation: call only after the user has explicitly confirmed this exact action and content in chat. It does not name alternative tools or describe what to do when confirmation is absent, but the gating condition is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
favoriteA
Favorite (action='create') or unfavorite (action='destroy') a status. WRITE ACTION: only call after the user has explicitly confirmed this exact action and content in chat. Requires confirm=true.
| Name | Required | Description | Default |
|---|---|---|---|
| action | No | create | |
| confirm | No | ||
| status_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose the key trait: this is a WRITE ACTION requiring explicit user confirmation and confirm=true, which is exactly the safety context an agent needs. It omits auth requirements, rate limits, and what happens if confirm is omitted/false (default false is only visible in the schema).
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?
Two tight sentences with the core capability first and the safety gate second. No filler, and the critical constraint is capitalized and front-loaded rather than buried.
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 3-parameter write tool with no annotations and no output schema, the description covers the essential behavioral contract (write + confirmation). It would be fully complete with a note on return behavior or failure when confirm is absent, but nothing needed to invoke 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 0%, so the description must compensate, and it does: it explains the two meaningful values of 'action' ('create' vs 'destroy') and the required 'confirm=true' semantics, which the bare schema does not. 'status_id' is left unexplained but is self-evident from the purpose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource pair ('favorite/unfavorite a status') and clarifies that a single tool handles both directions via the action parameter. This distinguishes it from the sibling 'favorites' (a listing tool) and 'post_status'/'delete_status' without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear gating condition: only call after the user has explicitly confirmed this exact action and content in chat, plus the confirm=true requirement. It does not name alternative siblings (e.g., 'favorites' for reading), but the when-to-use context is explicit and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
favoritesC
Read a user's favorited statuses (empty = the authenticated user).
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | ||
| count | No | ||
| user_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. 'Read' implies a non-mutating call, but pagination behavior (page/count interaction), result limits, ordering, and auth requirements are all unstated for a tool with three parameters.
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?
A single short sentence, front-loaded with the resource and action, with the scoping rule appended. No wasted words, though the brevity is partly under-specification rather than pure economy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, but with 0% schema coverage the description should compensate for the undocumented page/count parameters and lack of any read-only or auth statement. As written, an agent must guess at pagination semantics.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description only clarifies one of three parameters (user_id defaults to the authenticated user). The meaning of 'page' and 'count' — units, defaults, interaction — is left entirely undocumented in both schema and description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Read ... favorited statuses'), which is clear on its own. It implicitly distinguishes from the sibling 'favorite' (the write action) but never says so explicitly, leaving a possible ambiguity between reading favorites and favoriting a status.
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 parenthetical 'empty = the authenticated user' gives a useful rule for when to omit user_id, but there is no guidance on when to use this versus home_timeline, user_timeline, or mentions. Usage is only implied by the resource name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
friendshipA
Follow (action='create') or unfollow (action='destroy') a user. WRITE ACTION: only call after the user has explicitly confirmed this exact action and content in chat. Requires confirm=true.
| Name | Required | Description | Default |
|---|---|---|---|
| action | No | create | |
| confirm | No | ||
| user_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden and does disclose the most important trait: this is a write action gated behind explicit confirmation and a confirm=true flag. It stops short of describing side effects on timelines, rate limits, or failure behavior.
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?
Two sentences, zero waste, with the operation mapping and the safety guardrail both front-loaded. Every sentence earns its place.
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 mutation tool with no annotations and no output schema, the description supplies the critical confirmation protocol. Remaining gaps are minor: whether unfollow also requires confirmation, and what a failed or rejected call returns.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate — and it does for the two non-obvious parameters: action ('create'=follow, 'destroy'=unfollow) and confirm (must be true for the write). user_id is self-evident from the name, leaving only minor gaps.
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 names the two specific operations (follow/unfollow) and maps them to the action values, fully disambiguating the opaque name 'friendship'. An agent can distinguish this from siblings like favorite or post_status without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states a clear precondition for use: only call after the user has explicitly confirmed the exact action and content in chat. It doesn't name alternative tools or when-not-to-use cases, but no sibling overlaps with follow/unfollow semantics.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_contextC
Get the conversation context (reply chain) of a status.
| Name | Required | Description | Default |
|---|---|---|---|
| status_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. 'Get' implies a read-only operation, but nothing is said about ordering, reply depth, pagination, or authentication requirements for the reply chain.
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?
A single compact sentence with no filler, and the scoping detail '(reply chain)' is front-loaded. It is arguably under-specified rather than verbose, but it wastes no words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value shape need not be explained, and the tool has only one parameter. However, with no annotations the description should say more about the reply-chain semantics (depth, ordering, pagination) to be fully callable.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% for the single required parameter status_id. The description only indirectly implies that the parameter identifies 'a status' and adds no format or source detail to compensate for the empty schema description.
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 (Get) and resource (the conversation context / reply chain of a status), and the parenthetical '(reply chain)' disambiguates it from the sibling get_status, which retrieves the status itself. It is clear without opening the schema, though it never names the sibling it differs from.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance and no mention of alternatives such as get_status or the various timeline tools. The agent must infer that this is for expanding a thread rather than fetching a single status.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_statusC
Get one status by id.
| Name | Required | Description | Default |
|---|---|---|---|
| status_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It reveals nothing about return shape, visibility/permission constraints (e.g., whether a private status returns an error), or error behavior for an unknown id. For a zero-annotation tool this is a notable gap.
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?
A single front-loaded sentence with zero waste. It is concise to the point of under-specification, but nothing is redundant or buried.
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 one required parameter, no output schema, and no annotations, the description should have compensated for all three. Instead it supplies only a bare purpose statement, leaving an agent without enough context to know what a successful or failed call yields.
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?
One parameter at 0% schema description coverage. 'by id' loosely signals that status_id is an identifier, but nothing is said about its format (numeric vs. string id), where to source it, or whether it is required — the schema marks it required but the description does not reinforce this.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with a scoping qualifier: 'Get one status by id.' The phrase 'one status' implicitly contrasts with the timeline siblings that return many statuses, but it does nothing to distinguish itself from get_user, get_context, or post_status.
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?
No guidance on when to use this versus home_timeline, mentions, or get_context, and no prerequisites stated. The agent must infer that it needs a status_id it obtained elsewhere.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_userA
Get a user's profile by id (empty = the authenticated user).
| Name | Required | Description | Default |
|---|---|---|---|
| user_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It discloses the empty-string default behavior, but says nothing about authentication requirements, whether the profile is public/private, or what happens on an unknown id, leaving the read-only safety profile only implied by the verb 'Get'.
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?
A single tight sentence with the key behavioral detail (empty = self) front-loaded in parentheses. No wasted words.
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 simple one-parameter read tool with no output schema or annotations, the description covers the essential selection key and the default case. Adding auth or error-behavior context would make it fully complete, but the gap is minor at this complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the lone parameter has only a bare default of "", so the schema alone is uninformative. The description compensates by defining the id semantics and the special empty-value case, fully covering the single parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Get a user's profile') and clarifies the retrieval key (by id). The parenthetical 'empty = the authenticated user' further sharpens scope, though it does not explicitly distinguish this lookup from timeline/status siblings.
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?
Implies usage by explaining the empty-id case, which tells the agent how to fetch the caller's own profile. However, it gives no when-to-use/when-not guidance relative to siblings like user_timeline or verify_credentials.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
home_timelineC
Read the authenticated user's home timeline (statuses from people they follow). count 1-60.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | ||
| count | No | ||
| max_id | No | ||
| since_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It discloses that this is a read operation and adds the 'count 1-60' constraint beyond the schema, but it omits authentication requirements, pagination behavior, and rate limits.
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 very tight and front-loaded, using two short sentences with no wasted words. The fragment 'count 1-60' is slightly abrupt but informative.
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 4-parameter read tool with an output schema and no annotations, the description is missing pagination semantics for max_id/since_id/page and any usage guidance. It covers the core purpose and count limit but is not complete enough to call the tool confidently without opening the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate for four undocumented parameters. It adds a useful count range, but says nothing about page, max_id, or since_id, leaving most parameter semantics unexplained.
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 and resource: 'Read the authenticated user's home timeline,' and parenthetically clarifies content as 'statuses from people they follow.' This distinguishes it from public timelines and mentions implicitly, but it does not explicitly name or differentiate from any sibling tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this tool versus alternatives like user_timeline, mentions, or public_timeline. The implied usage is clear from the purpose statement, but no exclusion or alternative routing is provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mentionsB
Read statuses that mention the authenticated user. count 1-60.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | ||
| count | No | ||
| max_id | No | ||
| since_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It does disclose that results are scoped to mentions of the authenticated user and states the valid count range (1-60), which is genuine behavioral context, but it says nothing about pagination behavior, auth requirements, or result ordering.
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?
Two short sentences, front-loaded with the core purpose and followed by the one constraint worth surfacing. No filler, though it is arguably under-specified rather than optimally concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained. For a simple read tool this is nearly adequate, but the total absence of parameter documentation and any usage/routing guidance leaves real gaps for an agent picking among many sibling feeds.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% across 4 parameters (page, count, max_id, since_id). The description only documents the count range and leaves page, max_id, and since_id entirely unexplained, so the documentation gap is largely uncompensated.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Read statuses') and scopes it to those mentioning the authenticated user, which distinguishes it from the timeline siblings (home_timeline, user_timeline, public_timeline). It never names a sibling explicitly, but the 'mention the authenticated user' qualifier is enough to route correctly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance and no mention of alternatives. Given the crowded set of timeline/search siblings, an agent has to infer that this is the mentions-only feed rather than home_timeline or search_public_timeline.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
post_statusA
Post a new status (发饭). Optional in_reply_to_status_id / repost_status_id. WRITE ACTION: only call after the user has explicitly confirmed this exact action and content in chat. Requires confirm=true.
| Name | Required | Description | Default |
|---|---|---|---|
| status | Yes | ||
| confirm | No | ||
| repost_status_id | No | ||
| in_reply_to_status_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose the key behavioral traits: this is a WRITE ACTION, it requires explicit user confirmation, and it needs confirm=true. It omits irreversibility, rate limits, and what the call returns, so not a 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?
Front-loaded with the action, then the optional threading params, then the safety constraint. Every clause carries information and nothing is padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A write tool with no annotations, no output schema, and 0% parameter coverage needs more than this. The safety/confirmation guidance is solid, but the threading and repost parameters remain opaque and no return behavior is indicated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% across 4 parameters, so the description must compensate. It names in_reply_to_status_id and repost_status_id and flags confirm, but supplies no meaning, format, or valid-value guidance, and never explains the required 'status' parameter beyond the verb.
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 ('Post a new status'), which clearly distinguishes it from read siblings like get_status and destructive siblings like delete_status. It stops short of naming any sibling explicitly, but the purpose is 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?
Gives an explicit when-to-call condition: only after the user has explicitly confirmed the exact action and content in chat, plus the confirm=true requirement. It does not name when-not to use it or route to alternative write tools (favorite, friendship), so it falls short of the top band.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
public_timelineC
Read the latest public statuses on Fanfou. count 1-60.
| Name | Required | Description | Default |
|---|---|---|---|
| count | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. 'Read' implies a safe read operation, but it says nothing about authentication requirements (Fanfou timelines typically need a session), rate limits, or ordering/refresh semantics, leaving real gaps for a network-backed tool.
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?
Two short, front-loaded fragments with no filler; the purpose leads and the constraint follows. The second fragment ('count 1-60') is telegraphic, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the one parameter is at least bounded. Still missing are auth requirements and how this feed differs from the sibling timelines, which an agent needs to select it 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 0%, so the description must compensate for the single 'count' parameter. It usefully supplies the valid range (1-60) that the schema omits, but does not mention the default of 20 or what happens on out-of-range input, so the compensation is partial.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: 'Read the latest public statuses on Fanfou,' which tells an agent exactly what data comes back. However, it offers no differentiation from close siblings like home_timeline, user_timeline, or search_public_timeline, so the agent must infer that 'public' means unauthenticated/global feed.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance, no contrast against the five sibling timeline tools, and no prerequisites or auth context. The only supplemental text ('count 1-60') is a parameter constraint, not usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_public_timelineC
Search public statuses by keyword (supports 'a b' AND and 'a|b' OR).
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | ||
| count | No | ||
| max_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden, yet it only discloses query operator syntax. It says nothing about auth requirements, rate limits, pagination behavior, or that this is a read-only lookup, which matters for a tool with a max_id cursor.
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?
A single tight sentence with the resource up front and the syntax detail in parentheses. Nothing is wasted, though there is little content overall.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be described, but with no annotations and 0% parameter coverage the definition should still cover pagination (max_id), result limits, and access constraints. Those omissions leave an agent unable to page or scope results reliably.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and there are three parameters. The description usefully explains the 'a b' AND / 'a|b' OR syntax for q, but count and max_id are left entirely undocumented in both schema and description, so pagination semantics are lost.
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 clear verb and resource ('Search public statuses by keyword') and the 'public' qualifier implicitly separates it from search_user_timeline and public_timeline. It stops short of explicitly naming which sibling to prefer, so it's clear but not fully differentiated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use guidance, no mention of alternatives (e.g. search_user_timeline for a single account), and no stated prerequisites. Usage is only inferable from the word 'public' in the resource.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_user_timelineB
Search within one user's statuses (user_id empty = the authenticated user).
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | ||
| count | No | ||
| max_id | No | ||
| user_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure and delivers very little. It does not state authentication requirements, rate limits, pagination behavior (relevant given a max_id param), or result ordering. Only the user_id default behavior is disclosed.
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?
A single tight sentence with the scoping condition front-loaded and no filler. It is efficient but leans on the reader to infer the rest, which is under-specification rather than a structural flaw.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, which lightens the burden. Still, four undocumented parameters, no annotations, and no mention of auth or pagination leave meaningful gaps for a search tool with a required query parameter.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate and largely does not. It explains only user_id's default semantics; q, count, and max_id are left with bare titles, and the pagination meaning of max_id (return results before this ID) is never conveyed.
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 names a specific verb (search) and a bounded resource (one user's statuses), and the parenthetical scope makes it clear this is a per-user timeline search rather than a global one. It does not explicitly name competing siblings like user_timeline or search_public_timeline, so differentiation is only implied by scope wording.
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 parenthetical 'user_id empty = the authenticated user' gives a concrete default behavior an agent can act on. However, it never states when to prefer this over user_timeline (unfiltered list) or search_public_timeline (global search), so selection guidance is only inferable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
user_timelineB
Read a user's statuses. user_id empty = the authenticated user. count 1-60.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | ||
| count | No | ||
| max_id | No | ||
| user_id | No | ||
| since_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It does disclose the read-only nature ('Read') and the count range constraint ('count 1-60'), but omits pagination behavior and auth requirements. Useful but incomplete for a no-annotation tool.
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?
Three short, front-loaded clauses with no filler; the core purpose leads and constraints follow. Efficient, though its extreme terseness is what leaves the pagination parameters unexplained.
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 five parameters at 0% schema coverage and no annotations, the description is too sparse: the ID-based pagination fields (max_id, since_id, page) are essential to calling this correctly and are never described. An output schema exists, so return values need not be covered, but the input side remains under-specified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate for all five parameters. It clarifies user_id (empty = authenticated user) and count (1-60), but leaves page, max_id, and since_id entirely undocumented, and these cursor parameters are non-obvious without explanation.
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 ('Read a user's statuses'), which clearly maps to a timeline-fetch tool. It does not explicitly differentiate from close siblings like home_timeline or search_user_timeline, but the user_id default hint gives enough to separate it from the authenticated-user variants.
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?
'user_id empty = the authenticated user' implies when to use it for self vs. another user, which is genuine contextual guidance. However, there is no explicit when-to-use/when-not guidance relative to siblings such as home_timeline or mentions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_credentialsA
Return the authenticated Fanfou account (read-only).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden, and it does disclose the read-only, no-side-effect nature plus what is returned. However it omits auth-failure behavior (e.g. what happens with an invalid token) and any note that this doubles as a credential check, which is the key trait of a verify endpoint.
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?
A single short sentence, front-loaded with the return value and its scope qualifier. No filler, nothing repeated from structured fields.
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 zero-parameter read-only call with no output schema, the description gives what an agent needs: the returned entity and its authenticated scope. It is slightly thin on return shape and error behavior, but those are minor for a tool this simple.
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 tool takes zero parameters, so the baseline of 4 applies; there is nothing for the description to disambiguate beyond what the empty schema already conveys.
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 ('Return the authenticated Fanfou account') with the scope qualifier 'authenticated', which distinguishes it from sibling get_user. It doesn't explicitly name that sibling, so it falls short of the top mark.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the word 'authenticated' hints this is the identity/auth-check call rather than an arbitrary profile lookup. There is no explicit when-to-use or when-not-to-use statement and no reference to get_user as the alternative.
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.
15 tool updates
v0.1.0- First observed
delete_status - First observed
favorite - First observed
favorites - First observed
friendship - First observed
get_context - First observed
get_status - First observed
get_user - First observed
home_timeline - First observed
mentions - First observed
post_status - First observed
public_timeline - First observed
search_public_timeline - First observed
search_user_timeline - First observed
user_timeline - First observed
verify_credentials
TDQS
Scored across 15 tools
Most tools have clearly distinct resource+scope (home_timeline vs user_timeline vs public_timeline vs mentions are separated by audience, not confused). The one real overlap is verify_credentials versus get_user with an empty id, which both return the authenticated user, and the two search_* variants could be momentarily confused. Otherwise boundaries are clean.
The set mixes verb_noun (get_user, get_status, post_status, delete_status) with bare-noun reads (home_timeline, user_timeline, mentions, favorites) and bare-noun writes (favorite, friendship). The convention is readable and mostly predictable, but the inconsistent use of get_/search_ prefixes across reads keeps it from being fully uniform.
15 tools is at the upper edge of the well-scoped band but each one maps to a distinct Fanfou operation (timelines, search, status lifecycle, favorites, follow, context). Nothing feels redundant enough to cut. Slightly heavy but justified by the surface.
Core lifecycle is covered: read/search timelines, get status and reply context, post/delete, favorite/unfavorite, follow/unfollow. Gaps exist (no follower/following lists, no direct messages, no user search), but these are minor for the primary microblogging workflows an agent would run.
Maintenance
Related MCP Connectors
Hosted X (Twitter) MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
Mastodon MCP — public Mastodon data via mastodon.social (no auth required)
Twitter/X read-only MCP server — 12 tools: search, users, tweets, followers, timelines, trends.
- QuallaaOAuthcom.quallaa
Talk to your public-facing AI from any MCP client — Claude, ChatGPT, Cursor, Cline, Windsurf.
Related MCP Servers
- AlicenseBqualityDmaintenanceMCP server for interacting with the X platform (Twitter) via MCP clients like Claude, Cursor AI, and Windsurf AI.201 npm6MIT
- AlicenseAqualityAmaintenanceMCP server to read X (Twitter) posts, threads, replies, quotes, and search using your own logged-in session, no API key required.83MIT
- AlicenseNot gradedqualityBmaintenanceTwitter/X MCP server for the API v2, enabling users to manage profiles, posts, likes, retweets, and follows through natural language using a stateless Streamable HTTP transport with OAuth user access token authentication.9 npmISC
- FlicenseNot gradedqualityCmaintenanceEnables MCP-based interaction with the X (Twitter) API v2, supporting reads like timeline, mentions, and search, and writes through a two-step draft-and-confirm process that ensures human-visible previews before any public post.-