Install
go install github.com/SohrabZ/x-browser-mcp@latest
Added
read_mentions reads the posts that mention you, and read_notifications reads
the rest: likes, follows, reposts and X's own recommendations. Both are also
GET /api/v1/mentions and GET /api/v1/notifications, and read_x_url resolves
either notification URL.
- Notifications are their own shape rather than posts, because the page is not a
timeline of them: on a real account one cell in eighteen held a post. A
notification carries the words X wrote, the accounts it names, and when — and
keeps X's aggregation, so a cell saying two accounts liked one post stays one
notification with two actors. There is no post id or URL, because a cell links
only to the accounts involved. kind is read from X's own words, so it is empty
under a different interface language and for the cells X renders as nothing but a
name and a time.
AGENTS.md records what this project has cost to learn: the build gates, the
design decisions that are not inferable from the code, and the gotchas — X
ignoring synthesized mouse events on its engagement controls, a reply composer
discarding text typed before it is focused, rod's idle wait being a minimum
rather than a maximum. CLAUDE.md imports it rather than repeating it.
Fixed
- A failure told a caller the message of the error it arrived wrapped in rather
than the one that was recognised, and a wrapper is where the internals are: a
profile already in use carries the path of the lock that says so. The MCP tools
handed that to a model, into the same context as untrusted post text; the HTTP
write path did the same. Both now report the recognised message and nothing else,
and an unrecognised failure says only that there was one, with the detail going
to the log.
- A link
read_x_url could not read — not an x.com URL, no post id in it, a search
with no query — was reported as a server fault instead of as the caller's
mistake.
- Liking, reposting or bookmarking a deleted or private post was reported as a
server fault. It now says the post is not there, which is an answer rather than
something to retry.
- The message quoting a rejected URL back is bounded. It is the caller's own input,
but one reader of these messages is a model, and an unbounded message is a way to
fill a context window with a single bad request.