Skip to content

execute_playwright_code: drop replays + browser lifecycle; add manage_replays tool#124

Open
dprevoznik wants to merge 7 commits into
mainfrom
hypeship/playwright-drop-replays
Open

execute_playwright_code: drop replays + browser lifecycle; add manage_replays tool#124
dprevoznik wants to merge 7 commits into
mainfrom
hypeship/playwright-drop-replays

Conversation

@dprevoznik

@dprevoznik dprevoznik commented Jul 16, 2026

Copy link
Copy Markdown

Summary

Splits browser lifecycle and replay recording out of execute_playwright_code and 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_code

Every call wrapped the run in replays.start / replays.stop and validated existing sessions with browsers.retrieve, so an existing-session call made four sequential round tripsretrievereplays.startexecutereplays.stop — when only execute is 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_url from the response, and dropped the pre-execute browsers.retrieve validation (execute surfaces a not-found error on its own).

2. Make execute_playwright_code a passthrough — no browser lifecycle

session_id is now required. The tool no longer creates a stealth browser when session_id is omitted, and no longer deletes the browser afterward. It's now a thin wrapper over browsers.playwright.execute — inputs in, outputs back. Session lifecycle belongs to manage_browsers.

3. Add manage_replays tool

New replays toolset (src/lib/mcp/tools/replays.ts), backing browsers.replays with start / stop / list actions, gated by KERNEL_MCP_DISABLED_TOOLSETS like 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. start takes optional framerate, max_duration_in_seconds, and record_audio.

⚠️ Breaking change

Callers that relied on omitting session_id to get a one-shot, auto-created-and-deleted browser must now:

  1. create a session with manage_browsers (action create),
  2. pass its session_id to execute_playwright_code, and
  3. delete it with manage_browsers when done.

Callers wanting a video replay must now manage_replays start/stop around their calls instead of reading replay_url off each response. Existing callers that already pass a session_id and don't use the replay URL are otherwise unaffected.

Follow-ups (not in this PR)

  • computer_action latency/defaults tweaks (reword away from batch-by-default, viewport-default screenshots).
  • Consider giving execute_playwright_code a fuller description again — it's now a short one-liner, and more usage guidance could help agents use it correctly.

Testing

  • tsc --noEmit and prettier --check pass.
  • Verified end-to-end against a live server using the MCP Inspector CLI:
bun run dev  # starts on :3002

npx -y @modelcontextprotocol/inspector --cli http://127.0.0.1:3002/mcp \
  --transport streamable-http \
  --header "Authorization: Bearer $KERNEL_API_KEY" \
  --method tools/list
# ...and --method tools/call --tool-name <tool> --tool-arg key=value

Confirmed: manage_replays is registered; execute_playwright_code requires session_id and returns no replay_url; a browser is not deleted after execute (lifecycle removed); omitting session_id is rejected; and manage_replays start/stop/list all work.

Two gotchas when running the Inspector: use 127.0.0.1 (not localhost, 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, so bun run dev boots clean.


Note

Medium Risk
Breaking change for agents that omitted session_id or depended on automatic replay_url; behavior change on a high-traffic automation path but logic is simpler and delegated to existing SDK APIs.

Overview
Breaking MCP contract change: execute_playwright_code is now a thin wrapper around browsers.playwright.executesession_id is required, with no implicit browser create/delete and no per-call replay recording. Responses no longer include replay_url, and the extra retrieve / replays.start / replays.stop round trips on each call are removed.

New opt-in replay surface: Registers a replays toolset and manage_replays (start / stop / list on a session, optional framerate, duration, and audio on start), gated like other toolsets via KERNEL_MCP_DISABLED_TOOLSETS (documented in .env.example).

Docs: README and AGENTS.md describe the new workflow (create session → execute → optional manage_replays; MCP Inspector testing notes).

Reviewed by Cursor Bugbot for commit 8b3e732. Bugbot is set up for automated code reviews on this repo. Configure here.

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>
@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mcp Ready Ready Preview, Comment Jul 17, 2026 3:36am

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>
@dprevoznik dprevoznik changed the title Remove per-call replay recording from execute_playwright_code Make execute_playwright_code a lean passthrough (drop replays + auto browser lifecycle) Jul 16, 2026
dprevoznik and others added 2 commits July 16, 2026 20:53
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>
@dprevoznik dprevoznik changed the title Make execute_playwright_code a lean passthrough (drop replays + auto browser lifecycle) execute_playwright_code: drop replays + browser lifecycle; add manage_replays tool Jul 16, 2026
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>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ 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.

);
return itemsJsonResponse(replays, {
emptyText: "No replays found for this session",
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List skips pagination contract

Medium Severity

manage_replays list calls browsers.replays.list with only session_id and returns via itemsJsonResponse, without paginationParams or paginatedJsonResponse. Other MCP tool list actions expose limit/offset and return { items, has_more, next_offset }, so this path breaks the shared list contract agents rely on.

Fix in Cursor Fix in Web

Triggered by learned rule: MCP resources iterate all pages; tool list actions return single pages

Reviewed by Cursor Bugbot for commit 1265a2d. Configure here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not applicable here — the SDK's browsers.replays.list(id) returns a plain Array (ReplayListResponse), not a paginated page. There's no limit/offset/cursor to honor (unlike extensions.list/proxies.list, which return a page object), so it returns every replay for the session in one call. itemsJsonResponse still emits the shared { items, has_more, next_offset } envelope, so agents get the same shape. Adding paginationParams would advertise pagination the endpoint doesn't support. Leaving as-is.

@dprevoznik dprevoznik left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed mcp changes locally and breaking decision to simplify playwright execution tool.

@dprevoznik
dprevoznik requested a review from masnwilliams July 17, 2026 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant