Browser-native AI agents for X (Twitter): multi-account, MCP-ready, no API keys required.
x-use demonstrates strong definition quality with 26 well-named tools covering account management, proxy configuration, queue operations, and X (Twitter) interactions. Most tools have clear, action-oriented names (get_account, add_account, search_tweets) and comprehensive descriptions (100-400 chars typical). Input schemas are present and documented with parameter descriptions. However, there are notable gaps: output schemas are not documented in the provided code; several tools lack explicit error handling guidance; and some parameter relationships are underdocumented. The codebase shows careful attention to security (secrets never in params, server-side cookie import), but composition could be tighter, some tools combine multiple concerns (e.g., research_and_stage searches, filters, drafts, and stages in one call). Overall, this is a mature tool set that exceeds typical community servers but falls short of production-grade A-tier due to missing output documentation and incomplete error recovery patterns.
Add an account to config/accounts.json (validated, backed up, atomic). `cookie_file` is a path ON THIS MACHINE to an exported x.com cookies JSON; it is validated and copied to config/<account_id>_cookies.json. Cookie values never pass through the tool call. `persona` is freeform markdown describing the account's voice/engagement style (max 4000 chars).
Add a proxy URL to a named pool (created if new) in settings.json. Validated, deduped, backed up, atomic. Credentials are masked in the response. Assign it to accounts via update_account(proxy="pool:<name>") or a direct URL.
Cancel a pending or failed queued action. Done, processing, and already-cancelled items cannot transition.
Generate `count` distinct takes on a topic with the server-side LLM (persona-aware) and stage each as a post DRAFT. Nothing is posted, approve one and reject the rest. Requires the 'llm' block in settings.
Show one account's masked config (no cookies, no password, proxy credentials masked) plus cookie-file status. Read-only, never starts a browser.
Output schemas not documented: Tool descriptions lack explicit documentation of return types and response structure. LLMs cannot reliably extract chaining IDs (e.g., account_id after search_tweets) without seeing response schemas.
Composite tools combine multiple responsibilities: research_and_stage orchestrates search → filter → LLM draft → stage in one call. This prevents LLMs from composing steps independently and limits flexibility.
Error handling lacks recovery guidance: Tool descriptions identify errors (e.g., 'account not found') but do not suggest recovery actions like 'Call list_accounts to see available account IDs'.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 69 | <=2025-11-25 | v2 |
Read-only health snapshot for one account: config presence, cookie-file validity, metrics counters, warm-session state, queue depth, pending drafts. Never starts a browser. A config that fails validation is REPORTED (config.valid=false with the error), not raised, surfacing that is the point of a health check.
Show one draft by id. Read-only.
Read recorded metrics for an account (counters + recent events). Read-only, never starts a browser.
Poll run_cycle handles. With `run_id` omitted, lists every run started since this server booted. Read-only.
Read-only fetch of one tweet by URL or id. Returns the full tweet object with media, metrics, and author metadata. `include_images=true` attaches the tweet's images as content.
List configured accounts with secrets stripped (no cookies, no passwords, proxy credentials masked). Read-only, never starts a browser.
List drafts, newest first. `status` filters to one of pending/approved/executed/failed/rejected; `account` filters by account id; `limit` caps the response (max 100). Read-only.
List proxy pools (size, masked members, rotation cursor), the global pool strategy, each account's assignment, and the global fallback proxy. Read-only, never starts a browser.
List queued actions with their full payloads (exactly what will fire), plus per-status counts. Read-only, never starts a browser.
Drain queued actions with jittered pacing and daily caps. THIS CALL IS THE APPROVAL GATE for queued work: items execute through the same pacing/dedup/metrics path as every other write action. With `account` omitted, every account with due items drains concurrently.
Queue a like, retweet, or reply for paced execution. `action` is one of like/retweet/reply. reply requires `text` ("auto" scrapes the tweet and generates the reply NOW, so the stored payload is final). Nothing executes until process_queue is called.
Schedule a post for paced execution. Pass `text` verbatim, or a `topic` to generate the text NOW with the configured LLM (the stored payload is final, list_queue shows exactly what will be posted). `not_before` is an optional ISO 8601 timestamp. Nothing executes until process_queue is called (or auto_drain, if enabled).
Reject a pending draft so it can never be approved. Local status change only, nothing touches X.
Delete an account and its warm browser session (not its cookie file or metrics). Requires confirm=true.
Remove a proxy URL from a pool. Requires confirm=true. The response lists accounts still assigned pool:<name>. Emptying a referenced pool is allowed but reported (those accounts fall back to no proxy).
Search each keyword, keep relevant tweets (keyless heuristic), write a reply per tweet with the server-side LLM (persona-aware), and stage one reply DRAFT per tweet. Nothing is posted, review with list_drafts and approve selectively. Requires the 'llm' block in settings.
Read recent posts from ONE X profile. `profile` takes a handle ("@nasa" or "nasa"), a profile URL, or a tweet URL (which resolves to its author). Read-only (draft mode does not apply, nothing is posted), but it reuses the account's browser session. `account` defaults to the first active configured account. Use this to watch specific people and competitors, and to re-read one of your own published posts for its public counts; use search_tweets for topic and keyword discovery. Profile timelines include pinned posts and reposts, so check `user_handle` before treating a result as the profile owner's own writing. `include_images=true` additionally attaches the first photo of up to 5 posts as image content (bounded); the per-post `media` URLs + alt text are always present.
Search recent X posts for a query string. Read-only (draft mode does not apply). Reuses the account's warm browser session. `account` defaults to the first active configured account. `include_images=true` additionally attaches the first photo of up to 5 tweets as image content (bounded); the per-tweet `media` URLs + alt text are always present.
Enable or pause an account. Paused accounts reject queue and write work, but read (search, get_tweet) and config ops remain available.
Probe a proxy with a throwaway browser: resolves the effective proxy (explicit proxy_url wins; otherwise the account's direct URL or pool:<name> assignment), opens an IP-echo page, and reports the egress IP + latency. The probe browser is throwaway and cookieless, never account cookies or the warm session pool, but startup performs an anonymous x.com/home load before the IP-echo fetch, so latency_ms includes browser boot. With a round_robin pool, probing via `account` advances the pool's rotation cursor. Credentials masked in the response.
Partially update an account. Only provided fields change (None = leave unchanged); pass an empty string to clear `proxy`. `persona` sets the freeform persona text; pass an empty string to clear it. `cookie_file` re-imports cookies like add_account. The account's warm browser session is closed, so the new settings apply on next use.
Parameter relationships underdocumented: queue_post accepts both 'text' and 'topic'; if topic is provided and LLM fails, the payload is incomplete. Mutual exclusivity and dependency chains are not spelled out.
Numeric bounds missing: max_items, count, limit parameters lack explicit min/max in parameter descriptions. LLMs may pass invalid values (e.g., count=100 when max is 5).