You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Testing the BrowserOS MCP server (mcp__browseros__* tools, accessed via a Claude Code MCP client over the HTTP transport) surfaced a cluster of bugs across three areas: tools that never return their actual payload, several interaction/reporting inconsistencies, and infrastructure instability (server port drift + a recurring MCP client config regression). Confirmed reproducible across two testing sessions and two server versions (0.0.115 and 0.0.124, i.e. after upgrading specifically to check whether these were already fixed).
Environment
BrowserOS app version: 0.46.25.0
Agent server version: reproduced on both 0.0.115 and 0.0.124 (upgraded mid-testing via browseros-cli install specifically to check whether these were fixed in the latest release — they were not)
Chromium: 148.0.7948.97
macOS (Darwin 25.5.0, arm64)
browseros-cli 0.2.2 initially, 0.4.0 available
Client: Claude Code, MCP over HTTP ({"type":"http","url":"http://127.0.0.1:<port>/mcp"})
Data-return bugs (core pattern)
snapshot, read, grep, and run never return their actual payload inline — only metadata ({"page":N}, {"count":N}, {"ok":true}, {"contentLength":N,"writtenToFile":false}). Confirmed the underlying data is real and retrievable via evaluate (which works correctly), so this isn't a case of the data not existing — it's just never surfaced in the tool response.
Refinement of Needs steps/guide on how to run the project locally in README.md #1: snapshot/read do return a real, usable file path once content crosses a size threshold (roughly tens of KB). Below that threshold, both the file path and the inline text are missing — the content isn't just hidden behind a path, it's lost entirely for small pages.
run's return value and console.log output have no such size-based fallback — the response is always exactly {"ok":true} regardless of payload size. Only thrown exceptions surface (as the error message). This makes run effectively non-functional for its stated purpose (multi-step JS + data extraction).
grep's match count is accurate but it never returns the matched lines themselves — same metadata-only pattern as Needs steps/guide on how to run the project locally in README.md #1. Reproduced with a simple case-sensitive literal pattern known to match visible page text.
This looks related to #1376 (structured results for screenshot/grep/diff) and #1417 (screenshot missing structured image data, fixed in agent-server 0.0.124) — but unlike screenshot, snapshot/read/grep/run are still broken on 0.0.124, so whatever fixed screenshot's structured-content handling didn't extend to these.
Interaction / reporting bugs
Keyboard input (type/type_at/press) silently no-ops on background (non-focused) tabs — no error is raised, changed:false is returned, and the target field never receives the text.
act's changed flag and diff are unreliable in both directions: a verified real DOM change (a checkbox toggle) was reported as changed:false/"no change"; conversely, under a corrupted ref-map condition, fill reported changed:true when nothing had actually happened.
press with key "Enter" doesn't trigger native form submission, even on a correctly focused/filled field. Clicking the submit button (by ref, or via click_at) works fine as a workaround.
act kind scroll reliably timed out in original testing. A later retest didn't hang, but that retest was on a page with nothing to scroll, so it's inconclusive whether this is actually fixed.
drag_at did not perform HTML5-native drag-and-drop. Plausibly a generic pointer-event automation limitation rather than a BrowserOS-specific bug (a known hard case for automation generally).
Minor: tab_groupsaction:"create" ignores the color parameter (always returns "grey"); a follow-up action:"update" with the same color does apply correctly.
Infrastructure / stability bugs
The local BrowserOS agent server can crash under heavy synthetic DOM load — injecting ~3000 filler DOM elements (used as a stress-test workaround while investigating Using Releases instead of a private beta download portal #2) preceded the local server refusing all connections, reproduced twice.
The registered MCP client config's "type":"http" field gets dropped, and the server's port changes, recurringly. Hit 3 times in one day across two testing sessions: on the original re-add, again after the server crash/restart in Does it support file uploading? #11, and then a third time spontaneously mid-session with no heavy load in progress (port cycled 9200 → 9202 → 9200 with no action on our end). Because it recurred with no corresponding client-side action, this doesn't look like purely a crash-recovery artifact — something appears to intermittently regenerate or touch the MCP client registration. Not certain what's writing it; flagging in case BrowserOS (the app, browseros-cli launch/init, or an auto-configure-MCP-clients feature) is the one touching third-party AI client configs like ~/.claude.json, and doing so without the type field.
Fixing the client registration mid-session never takes effect in that same session — claude mcp list/curl confirm the server is healthy and the config is correct, but the already-running session's tool transport stays bound to whatever was configured at session start. A brand-new client session is required every time the port/config changes. (This may be more a property of the MCP client than BrowserOS itself, but it makes the port-drift bug in "Google API keys are missing. Some functionality of Chromium will be disabled." error/warning message #12 considerably more disruptive in practice, since every drift requires restarting the AI client session, not just re-pointing config.)
Separately, this also relates to open issue #1514 (server drops mid-session, rebinds between ports 9200/9201) — we hit the same class of instability, but observed a 3-port cycle (9200→9202→9200) rather than the 2-port cycle described there, and tied it to the registration's type field going missing.
Not a bug (documented quirk, for context)
search_documentation's keyword matching is literal, not semantic (as it discloses in its own description) — a query like "create issue" surfaced repo/org-creation actions before the actual GITHUB_ISSUES.create action. Not filing this as a bug, just noting it since it came up during the same testing pass.
Why this matters
Together, #1-4 make the snapshot → act(ref) loop — the documented core automation pattern — unusable as designed: no [ref=eN] handles are ever returned, so ref-based act kinds and ref-based download/upload can't be driven at all. The only reliable workaround found is evaluate (CDP Runtime.evaluate) for reads plus coordinate-based act kinds (click_at, type_at, etc.) for interaction — screenshot and evaluate were the only two tools that behaved correctly and consistently across all testing.
Happy to provide raw request/response logs for any of these if useful — let me know which ones would help most.
Summary
Testing the BrowserOS MCP server (
mcp__browseros__*tools, accessed via a Claude Code MCP client over the HTTP transport) surfaced a cluster of bugs across three areas: tools that never return their actual payload, several interaction/reporting inconsistencies, and infrastructure instability (server port drift + a recurring MCP client config regression). Confirmed reproducible across two testing sessions and two server versions (0.0.115 and 0.0.124, i.e. after upgrading specifically to check whether these were already fixed).Environment
browseros-cli installspecifically to check whether these were fixed in the latest release — they were not){"type":"http","url":"http://127.0.0.1:<port>/mcp"})Data-return bugs (core pattern)
snapshot,read,grep, andrunnever return their actual payload inline — only metadata ({"page":N},{"count":N},{"ok":true},{"contentLength":N,"writtenToFile":false}). Confirmed the underlying data is real and retrievable viaevaluate(which works correctly), so this isn't a case of the data not existing — it's just never surfaced in the tool response.snapshot/readdo return a real, usable file path once content crosses a size threshold (roughly tens of KB). Below that threshold, both the file path and the inline text are missing — the content isn't just hidden behind a path, it's lost entirely for small pages.run's return value andconsole.logoutput have no such size-based fallback — the response is always exactly{"ok":true}regardless of payload size. Only thrown exceptions surface (as the error message). This makesruneffectively non-functional for its stated purpose (multi-step JS + data extraction).grep's match count is accurate but it never returns the matched lines themselves — same metadata-only pattern as Needs steps/guide on how to run the project locally in README.md #1. Reproduced with a simple case-sensitive literal pattern known to match visible page text.This looks related to #1376 (structured results for screenshot/grep/diff) and #1417 (screenshot missing structured image data, fixed in agent-server 0.0.124) — but unlike screenshot,
snapshot/read/grep/runare still broken on 0.0.124, so whatever fixed screenshot's structured-content handling didn't extend to these.Interaction / reporting bugs
type/type_at/press) silently no-ops on background (non-focused) tabs — no error is raised,changed:falseis returned, and the target field never receives the text.act'schangedflag anddiffare unreliable in both directions: a verified real DOM change (a checkbox toggle) was reported aschanged:false/"no change"; conversely, under a corrupted ref-map condition,fillreportedchanged:truewhen nothing had actually happened.presswith key"Enter"doesn't trigger native form submission, even on a correctly focused/filled field. Clicking the submit button (by ref, or viaclick_at) works fine as a workaround.actkindscrollreliably timed out in original testing. A later retest didn't hang, but that retest was on a page with nothing to scroll, so it's inconclusive whether this is actually fixed.drag_atdid not perform HTML5-native drag-and-drop. Plausibly a generic pointer-event automation limitation rather than a BrowserOS-specific bug (a known hard case for automation generally).tab_groupsaction:"create"ignores thecolorparameter (always returns"grey"); a follow-upaction:"update"with the same color does apply correctly.Infrastructure / stability bugs
"type":"http"field gets dropped, and the server's port changes, recurringly. Hit 3 times in one day across two testing sessions: on the original re-add, again after the server crash/restart in Does it support file uploading? #11, and then a third time spontaneously mid-session with no heavy load in progress (port cycled 9200 → 9202 → 9200 with no action on our end). Because it recurred with no corresponding client-side action, this doesn't look like purely a crash-recovery artifact — something appears to intermittently regenerate or touch the MCP client registration. Not certain what's writing it; flagging in case BrowserOS (the app,browseros-cli launch/init, or an auto-configure-MCP-clients feature) is the one touching third-party AI client configs like~/.claude.json, and doing so without thetypefield.claude mcp list/curlconfirm the server is healthy and the config is correct, but the already-running session's tool transport stays bound to whatever was configured at session start. A brand-new client session is required every time the port/config changes. (This may be more a property of the MCP client than BrowserOS itself, but it makes the port-drift bug in "Google API keys are missing. Some functionality of Chromium will be disabled." error/warning message #12 considerably more disruptive in practice, since every drift requires restarting the AI client session, not just re-pointing config.)Separately, this also relates to open issue #1514 (server drops mid-session, rebinds between ports 9200/9201) — we hit the same class of instability, but observed a 3-port cycle (9200→9202→9200) rather than the 2-port cycle described there, and tied it to the registration's
typefield going missing.Not a bug (documented quirk, for context)
search_documentation's keyword matching is literal, not semantic (as it discloses in its own description) — a query like "create issue" surfaced repo/org-creation actions before the actualGITHUB_ISSUES.createaction. Not filing this as a bug, just noting it since it came up during the same testing pass.Why this matters
Together, #1-4 make the
snapshot → act(ref)loop — the documented core automation pattern — unusable as designed: no[ref=eN]handles are ever returned, so ref-basedactkinds and ref-baseddownload/uploadcan't be driven at all. The only reliable workaround found isevaluate(CDPRuntime.evaluate) for reads plus coordinate-basedactkinds (click_at,type_at, etc.) for interaction —screenshotandevaluatewere the only two tools that behaved correctly and consistently across all testing.Happy to provide raw request/response logs for any of these if useful — let me know which ones would help most.