Install
go install github.com/SohrabZ/x-browser-mcp@latest
Added
-write-timeout (default 2m) bounds one write. Writes shared
-fetch-timeout before, which is sized for a read: a write starts its own
browser, presses a control, waits for X's request and reloads the post to
confirm it, so a read's budget could cut the confirmation off and report a
timeout rather than a verdict.
TESTING.md records how to check that a write actually happened, and why the
check has to be indirect.
Changed
- An engagement action costs a request wait and a page reload — roughly 3-4s
more. The alternative is what it replaces: a tool that reports ok and
changes nothing.
Fixed
- A write reported that the click succeeded, not that the action happened. X
applies engagement over the network and swaps the control before its request
completes, so a click the page accepted and never sent looked identical to one
that worked. The request is waited on, and the post reloaded afterwards to
confirm the action survived a round trip.
- Anything that disturbed the page while that request was in flight cancelled
it — tearing the browser down, navigating, or reloading in order to check. A
check that read the page too eagerly caused the failure it was looking for.
- Synthesized mouse events do nothing on X's engagement controls. A like
dispatched through CDP was accepted by the page, raised no error, and made no
request. Those controls are pressed with a DOM click.
- A reply never reached the composer. The box stays collapsed until focused and
text entered into an unfocused one is discarded, so the box looked filled, the
submit button stayed disabled, and the click landed on a control that could
not be pressed. It is focused first, and the submit control waited on.
- An action could be applied to the wrong post. A permalink renders the post's
ancestors, its replies and any quoted post alongside it, each with a like,
repost and bookmark row of its own, and the checks matched the whole document
— so one reply you had already liked was enough for a like to report success
without touching the post asked for.
- Bookmark and repost had no confirmation selector, so they could only ever
report the click. Both have one.
- Closing a write browser raised Chrome's "Leave site?" prompt. The page-level
close runs beforeunload hooks and X registers one on its composer, so
teardown blocked on a dialog nobody was there to answer, holding the profile
until the shutdown wait gave up. Tabs are discarded at the target level.
- Each read leaked a page for the life of the process, because discarding a tab
at the target level skips the cleanup the page-level close does.
- A post id of anything but digits could not match a status link, so it fell
back to the first post on the page rather than failing. It is rejected before
a browser is opened.