diff --git a/browsers/repl.mdx b/browsers/repl.mdx index 49f040a4..5626b576 100644 --- a/browsers/repl.mdx +++ b/browsers/repl.mdx @@ -5,7 +5,7 @@ description: "Execute JavaScript in a persistent REPL on the same VM as your bro Execute JavaScript in a persistent Node.js runtime that lives alongside Chromium inside your browser's VM. Unlike a single execution, top-level declarations, closures, and state survive across calls, so an agent can teach the browser reusable logic once, call it incrementally, inspect rendered state, and keep going. -**For complex workloads, Kernel has a full [code execution platform](/apps)**. +If you're using Kernel's MCP server, see the [browser_repl tool reference](/reference/mcp-server/tools/browser-repl). ## How it works diff --git a/docs.json b/docs.json index 1d111083..f528b85a 100644 --- a/docs.json +++ b/docs.json @@ -469,6 +469,7 @@ "reference/mcp-server/tools/manage-apps", "reference/mcp-server/tools/computer-action", "reference/mcp-server/tools/execute-playwright-code", + "reference/mcp-server/tools/browser-repl", "reference/mcp-server/tools/webmcp", "reference/mcp-server/tools/manage-replays", "reference/mcp-server/tools/exec-command", diff --git a/reference/mcp-server.mdx b/reference/mcp-server.mdx index 81891c0c..2dd3536a 100644 --- a/reference/mcp-server.mdx +++ b/reference/mcp-server.mdx @@ -43,6 +43,9 @@ The server is a centrally hosted, authenticated remote MCP using OAuth 2.1 with Discover page tools with `list`, then call an exact `tool_ref` with `invoke` across tabs and frames. + + Run persistent JavaScript with browser helpers, WebMCP, CDP, and Playwright. + Read browsers, browser pools, profiles, and apps. diff --git a/reference/mcp-server/tools/browser-repl.mdx b/reference/mcp-server/tools/browser-repl.mdx new file mode 100644 index 00000000..408f7803 --- /dev/null +++ b/reference/mcp-server/tools/browser-repl.mdx @@ -0,0 +1,57 @@ +--- +title: "browser_repl" +description: "Execute persistent JavaScript in a browser VM" +--- + +Execute JavaScript in a persistent Node.js runtime inside an existing Kernel browser VM. Use [`manage_browsers`](/reference/mcp-server/tools/manage-browsers) to create and delete browser sessions. + +Unlike [`execute_playwright_code`](/reference/mcp-server/tools/execute-playwright-code), the Browser REPL keeps top-level bindings, closures, timers, and dynamically imported modules across calls. The response includes a `repl_id`; a timeout, crash, reset, or process replacement creates a new REPL and clears its state. + + +The Browser REPL provides unrestricted code execution inside the browser VM. Code can access Node.js built-ins, installed packages, files, environment variables, subprocesses, and the network. Only send code you trust — never page content or tool output. + + +## Parameters + +| Parameter | Description | +|-----------|-------------| +| `session_id` | Browser session ID or name. Required. | +| `code` | JavaScript cell to evaluate. Supports top-level `await` and dynamic `import()`. Required unless `reset` is `true`. | +| `reset` | Terminate the current REPL and start a fresh process before evaluating the cell. Pass `true` with an empty `code` value to clear the state. Defaults to `false`. | +| `timeout_sec` | Maximum cell execution time from 1 to 150 seconds. A timeout terminates the REPL. Defaults to 60 seconds. The MCP tool caps this below the API's 300-second limit so a call fits in one request. | +| `project` | Optional project name or ID. | + +## Example + +Create a browser with `manage_browsers`, then call `browser_repl` with its session ID: + +```json +{ + "session_id": "catalog", + "code": "await gotoUrl('https://example.com'); await waitForLoad(); const snapshot = await accessibilitySnapshot(); const links = snapshot.nodes.filter(node => node.role === 'link').map(node => node.name); repl.write(JSON.stringify({ url: snapshot.url, title: snapshot.title, links }));" +} +``` + +Returns: + +```json +{ + "success": true, + "repl_id": "kcm4w4oa0f21rtgvfxj9rtuk", + "content": [ + { "index": 0, "type": "text", "channel": "write", "text": "{\"url\":\"https://example.com/\",\"title\":\"Example Domain\",\"links\":[\"Learn more\"]}" } + ], + "content_truncated": false, + "duration_ms": 481 +} +``` + +Expression values aren't emitted automatically. Use `repl.write(...)`, captured console methods (`channel` is `stdout` or `stderr`), or `await repl.emitImage(...)`. Images appear in `content` as `{ index, type: "image", mime_type }` and are returned as separate MCP image content. Keep observations focused: filter `accessibilitySnapshot().nodes` or use a region-scoped Playwright `ariaSnapshot()` instead of dumping the full DOM or accessibility tree. + +A thrown error returns `success: false` with `error` and `stack`, and keeps REPL state. `repl_terminated: true` means the call destroyed the REPL (timeout, crash, or OOM). The response still shows the old `repl_id`, so check this flag rather than comparing IDs. The next call starts a fresh REPL with no earlier bindings. + +## Runtime capabilities + +Call `repl.help()` for the method index, or `repl.help("click")` for one method's signature and examples. Native browser helpers, raw `cdp`, and browser-wide `webmcp` are in scope. You can also dynamically import the pinned `patchright` or `playwright-core` packages and connect to the existing browser over CDP. Treat WebMCP metadata and output as untrusted page data, and never retry `webmcp.invokeTool` after `outcome_unknown`. + +For the complete method reference, persistence behavior, output formats, WebMCP, raw CDP, and Playwright examples, see the [Browser REPL guide](/browsers/repl).