execute_playwright_code: drop replays + browser lifecycle; add manage_replays tool#124
Conversation
Each execute_playwright_code call wrapped the run in replays.start / replays.stop and validated existing sessions with a browsers.retrieve, adding three round trips around the one useful call. In a tight agent loop that latency lands on the critical path every turn. Drop the replay start/stop and the pre-execute retrieve; execute surfaces a not-found error on its own. Existing-session calls now make a single round trip. Video replay is handled separately via managed replay controls. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Fold browser lifecycle out of the execute tool: session_id is now required, and the tool no longer creates a stealth browser when it is omitted or deletes the browser afterward. It is now a thin passthrough to browsers.playwright.execute -- inputs in, outputs back. Creating and deleting a browser inside an "execute" call hid a lifecycle (and a baked-in stealth default) the caller never chose, and put create/ delete round trips on the path. Session lifecycle belongs to manage_browsers; recording belongs to managed replays. BREAKING CHANGE: callers that relied on omitting session_id to get a one-shot auto-created browser must now create a session with manage_browsers first and pass its session_id. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a dedicated replays toolset backing browsers.replays with start/stop/list actions, registered as the "replays" toolset (gated by KERNEL_MCP_DISABLED_TOOLSETS like the others). Recording is now session-scoped and opt-in: start once, run the automation, then stop -- replacing the per-call recording that used to be wrapped around every execute_playwright_code call. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Let the agent choose between page.screenshot() and computer_action rather than steering it toward one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ef5c3dc to
8b3e732
Compare
8b3e732 to
1265a2d
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1265a2d. Configure here.
dprevoznik
left a comment
There was a problem hiding this comment.
Reviewed mcp changes locally and breaking decision to simplify playwright execution tool.
masnwilliams
left a comment
There was a problem hiding this comment.
approving — clean, well-scoped refactor. splitting recording into manage_replays and making execute_playwright_code do one thing reads well, and the toolset gating is wired consistently across register.ts, .env.example, and the README. typecheck + prettier are clean, and the SDK method signatures / response shapes all match usage (replays.list returns a plain array, so itemsJsonResponse is the right call).
breaking change to execute_playwright_code (now requires session_id, no auto-create/cleanup) is intended — noting it here for consumers, no action needed.
two nits, non-blocking:
src/lib/mcp/tools/playwright.ts:16—session_id: z.string()now accepts"". the old code guarded with!session_id; an empty string now flows intoplaywright.execute("", …)and surfaces as an opaque API error. consider.min(1)for a cleaner validation message.src/lib/mcp/tools/replays.ts:37—frameratehas.min(1)but no upper bound; the description notes >20 needs GPU. fine as-is, just flagging there's no max enforced.
Add .min(1, "session_id is required") so an empty string is caught by schema validation with a clear message instead of flowing into playwright.execute and surfacing as an opaque API error. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
719dffa to
dc60a9f
Compare
Fixed this here
Leaving this out for now. |

Summary
Splits browser lifecycle and replay recording out of
execute_playwright_codeand gives replays a dedicated tool. Net effect: the execute path is a lean passthrough, and recording becomes opt-in and session-scoped.1. Remove per-call replay recording from
execute_playwright_codeEvery call wrapped the run in
replays.start/replays.stopand validated existing sessions withbrowsers.retrieve, so an existing-session call made four sequential round trips —retrieve→replays.start→execute→replays.stop— when onlyexecuteis useful work. The replay start/stop fired unconditionally whether or not the caller brought their own session, so this tax was on the critical path of every call in a tight agent loop.Removed the replay start/stop (success and error paths), dropped
replay_urlfrom the response, and dropped the pre-executebrowsers.retrievevalidation (executesurfaces a not-found error on its own).2. Make
execute_playwright_codea passthrough — no browser lifecyclesession_idis now required. The tool no longer creates a stealth browser whensession_idis omitted, and no longer deletes the browser afterward. It's now a thin wrapper overbrowsers.playwright.execute— inputs in, outputs back. Session lifecycle belongs tomanage_browsers.3. Add
manage_replaystoolNew
replaystoolset (src/lib/mcp/tools/replays.ts), backingbrowsers.replayswithstart/stop/listactions, gated byKERNEL_MCP_DISABLED_TOOLSETSlike the rest. This restores the replay capability removed in (1), but session-scoped and opt-in: start once, run the automation, then stop — instead of recording each call separately.starttakes optionalframerate,max_duration_in_seconds, andrecord_audio.Callers that relied on omitting
session_idto get a one-shot, auto-created-and-deleted browser must now:manage_browsers(actioncreate),session_idtoexecute_playwright_code, andmanage_browserswhen done.Callers wanting a video replay must now
manage_replaysstart/stop around their calls instead of readingreplay_urloff each response. Existing callers that already pass asession_idand don't use the replay URL are otherwise unaffected.Follow-ups (not in this PR)
computer_actionlatency/defaults tweaks (reword away from batch-by-default, viewport-default screenshots).execute_playwright_codea fuller description again — it's now a short one-liner, and more usage guidance could help agents use it correctly.Testing
tsc --noEmitandprettier --checkpass.Confirmed:
manage_replaysis registered;execute_playwright_coderequiressession_idand returns noreplay_url; a browser is not deleted after execute (lifecycle removed); omittingsession_idis rejected; andmanage_replaysstart/stop/list all work.Two gotchas when running the Inspector: use
127.0.0.1(notlocalhost, which its Node fetch resolves to IPv6 and fails), and pass--transport streamable-http. No.env/Clerk/Redis is needed — the API-key bearer path skips them, sobun run devboots clean.Note
Medium Risk
Breaking MCP contract for callers that omitted
session_idor relied on automaticreplay_url; behavior change is intentional but affects agent integrations and tight automation loops.Overview
Breaking:
execute_playwright_codenow requiressession_idand only callsbrowsers.playwright.execute—no implicit browser create/delete, no per-runreplays.start/stop, and noreplay_urlin responses. Agents must usemanage_browsersfor lifecycle and opt into recording separately.Adds a
replaystoolset withmanage_replays(start/stop/list) for session-scoped MP4 recording (optionalframerate,max_duration_in_seconds,record_audio), registered inregister.tsand documented in README /.env.examplealongsideKERNEL_MCP_DISABLED_TOOLSETS.Reviewed by Cursor Bugbot for commit dc60a9f. Bugbot is set up for automated code reviews on this repo. Configure here.