Add browser pool parity fields to MCP#112
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| width, | ||
| height, | ||
| ...(params.viewport_refresh_rate !== undefined && { | ||
| refresh_rate: params.viewport_refresh_rate, |
Monitoring Plan: Add
|
|
Monitoring plan created for browser pool Affected services: kernel-mcp-server (Vercel Preview), api Key signals to watch (baseline: 24h pre-deploy):
Alert thresholds:
[View monitor] |
a5646b1 to
ea9503f
Compare
a74fdac to
55d4fca
Compare
masnwilliams
left a comment
There was a problem hiding this comment.
reviewed — large but well-structured: extracts shared helpers (responses.ts, browser-config.ts, resource-templates.ts) and brings browser pools to create/update parity. typechecks clean across the branch. this is the cleanup the earlier PRs were pointing at — resolves the duplicate textResponse, and the ResourceTemplate migration likely fixes "get one by URI" resources that the old static-URI + startsWith approach couldn't actually serve. also removes the dead extension-check from #110.
worth confirming before merge
- pool
updatesizecast (browser-pools.ts, ~updateParams as BrowserPoolUpdateParams): verifiedBrowserPoolUpdateParams.sizeis required in@onkernel/sdk@0.58.0, so the cast silences a real type error. it rests entirely on the comment's claim that the backend PATCH accepts partial bodies. if true → the SDK type is wrong, please file an SDK/OpenAPI fix and reference it here. if not → anupdatethat omitssize(e.g. just togglingheadless) will 4xx at runtime despite typechecking. this is the one real risk in the PR.
notes
- resource URI changed
browser_pools://→browser-pools://(hyphen). documented in the README diff so it's intentional — just confirm nothing external referenced the old underscore form. note the other three schemes stayed single-word (apps:///browsers:///profiles://), so this is the only one that changed.
agent-fit
no new concern — pool lifecycle (incl. flush/delete) is core. cross-cutting: still no MCP annotations on any tool; adding readOnlyHint/destructiveHint here would let clients auto-confirm reads and prompt on flush/delete.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Resolve the active Cursor profile pagination bug by preserving structured JSON for explicit empty pages, restore the cleaner computer_action structure from main with clipboard support, derive browser config payload types from the SDK, and remove stale dead types.
Remove emptyText from paginated response options so explicit empty pages always return items, has_more, and next_offset. Keep empty guidance only on non-paginated item responses and update app/browser list callers accordingly.
|
reviewed the full diff — solid refactor + additive feature. no lost functionality (every tool/action/param preserved; deletions moved into the shared helpers), SDK types are derived everywhere they should be, and nits
question
behavior changes worth a line in the PR body (not bugs — all defensible)
nice work — the net-negative line counts in browsers/profiles/apps are the good kind of churn. |
- Remove unused textResponse import in apps.ts (dead import) - Add .min(0) to browser pool fill_rate_per_minute so the schema rejects negatives; left unbounded above and non-integer since the SDK/API type it as a plain number (fractional/>100% rates are valid) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
thanks @masnwilliams — addressed in b3b3c74: nits
question — Keeping it hand-written; intentional. It's a generic helper consumed by every paginated endpoint ( Worth noting the exposure is narrower than it looks: (No test for that optional-field drift since there's no test runner in the repo yet — didn't want to pull a framework into this PR. Happy to add one separately if we want the insurance.) behavior changes Documented in the PR body now under a new "Behavior changes" section (out-of-range pagination rejection, |
Match the .int() validation used by sibling pool fields (size, timeout_seconds) per the MCP integer-param convention; fill rate percentages are whole numbers in practice. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Revert the .int() constraint: fill_rate_per_minute is a percentage, not a count, and the SDK/API type it as a plain number with no integer restriction, so .int() rejected valid fractional rates. Added a comment noting the intentional deviation from the sibling count fields. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The acquire next_actions echoed the caller's id_or_name (possibly a display name) in the release hint, while create/update use the stable pool id. Prefer browser.pool.id, falling back to id_or_name only when the SDK omits the pool ref, so follow-ups survive a pool rename. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Reviewed by Cursor Bugbot for commit 87a580c. Configure here.
buildPoolConfigParams included proxy_id whenever it was defined, so an empty string was forwarded to the API on pool create/update. Match the truthiness check manage_browsers create uses (and the sibling name field) so empty proxy_id is dropped; pools have no clear-proxy semantics for an empty string. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Summary
updatesupport to the existingmanage_browser_poolsMCP toolstart_url,chrome_policy,kiosk_mode, extension selection, profile ID/save settings, and viewport settingsdiscard_all_idlesupport without requiring agents to resend unchanged pool size/configmanage_browsersandmanage_browser_poolsnext_actions, stable pool-ID follow-ups, and structured SSH forwarding guidance{ items, has_more, next_offset }payloadschrome_policyobjects, and guarding nullish pool list responsescomputer_actionschema/execution structure from main while keeping clipboard support and integer validation from this stackWhy
discard_all_idleshould not force agents to resend unchanged pool size/configurationgetresponses for inspection, and explicit next-step guidance after create/update/acquire operationslimit/offsetstill provides paginated control when requestedAgent Experience / Flow
This PR gives agents a fast-session workflow for repeated browser work. Instead of creating a fresh browser for every task, an agent can configure a pool once, acquire pre-warmed sessions, use normal browser tools, and release sessions back into the pool.
Typical flow:
manage_browser_pools create size=<n> name=<name>with the same browser-shaping options it would otherwise pass tomanage_browsers create, such asprofile_id,start_url,chrome_policy,viewport_width, andextension_id.manage_browser_pools listfor a compact pool inventory andmanage_browser_pools get id_or_name=<pool_id>for full details.manage_browser_pools acquire id_or_name=<pool_id>to get a browser session.session_idwithcomputer_action,execute_playwright_code,browser_curl, orexec_command.manage_browser_pools release id_or_name=<pool_id> session_id=<id> reuse=truewhen the session can return to the pool, orreuse=falsewhen it should be discarded and replaced.manage_browser_pools update id_or_name=<pool_id>with only the fields it wants to change.sizeis required for create, but update accepts partial bodies such asdiscard_all_idle=true.flushto remove idle browsers without deleting the pool, anddeleteonly when the pool is no longer needed.Agent-facing response behavior:
manage_browser_pools create/updatereturns a compactbrowser_poolsummary plusnext_actions.manage_browser_pools acquirereturns a compact browser summary plusnext_actionsfor control/release/get-detail follow-up.manage_browser_pools listreturns compact summaries and points agents togetfor full details.id, not the display name.manage_browsers create/updatereturns structured JSON withbrowserandnext_actions.ssh_port_forwardinginstead of appended as mixed JSON + markdown.paginatedJsonResponse(page, { mapItem, note }); paginated empty pages always stay structured JSON withitems,has_more, andnext_offset.manage_profiles listkeeps the old agent-friendly default of returning the full matching inventory unless the caller explicitly asks forlimitoroffset.itemsJsonResponse, not through paginated responses.How
KernelClient["browserPools"]KernelClient["browsers"]andKernelClient["browserPools"]src/lib/mcp/browser-config.tssrc/lib/mcp/responses.ts, including separate item and paginated response helperssrc/lib/mcp/schemas.tssize; update allows partial configuration/update-only bodies and rejects only completely empty update requestschrome_policy: {}is ignored, so it does not count as a real update field or get sent to the APIgetcomputer_actionkeeps a single action schema and prefix executor so clipboard support does not split or duplicate the computer-use surfaceBehavior changes
Intentional changes worth calling out for reviewers (none are regressions):
limit/offsetat the schema level (.min/.max) instead of relying on the old silent API-side clamp.manage_appsandmanage_profilesnow setisError: trueinstead of returning plain content, so MCP clients surface them as errors.chrome_policy: {}is now dropped rather than sent as an update field.Validation
Static and build checks:
bunx prettier --check src/lib/mcp/responses.ts src/lib/mcp/tools/apps.ts src/lib/mcp/tools/browsers.ts src/lib/mcp/tools/profiles.tsgit diff --checkgit diff --cached --checkbunx tsc --noEmit --incremental falsebun run buildwith dummy deployment env and network access for Google FontsFocused checks from the latest commit:
itemsJsonResponse.items: [],has_more, andnext_offset.emptyTextis forced through at runtime.emptyTextis no longer part ofpaginatedJsonResponseoptions.Earlier PR validation retained:
manage_computer_action,manage_search_docs, and legacybrowser_utilitiesaliases disable the expected toolsets, and unknown disabled toolsets throw a clear error.chrome_policyreturns a clean MCP error instead of sending an empty update, non-emptychrome_policyis still sent and summarized, and nullish pool list responses returnNo browser pools found.http://localhost:3002/mcpverifiedinitialize,OPTIONS /mcp,tools/list,resources/list,prompts/list, schema assertions, andsearch_docsdummy-env behavior.isError: truefor pagination, pool size,browser_curl,computer_action,exec_command, andmanage_browsers updatevalidation paths.Platform/API smoke context:
403 Browser pools require a Start-Up or Enterprise plan.Notes
bun run format:checkstill fails on pre-existingAGENTS.mdmarkdown table formatting. This PR uses touched-file Prettier checks to avoid unrelated project-instruction churn.Note
Medium Risk
Broad MCP surface changes (pool updates, pagination validation, error
isErrorbehavior) could affect agent workflows; no auth changes but SDK upgrade ties behavior to 0.60.0 APIs.Overview
Extends
manage_browser_poolswithupdate, SDK parity fields on create/update (start_url,chrome_policy,kiosk_mode, extensions, profile ID/save, viewport,discard_all_idle), and bumps@onkernel/sdkto 0.60.0.browser-config.tscentralizes profile/extension/viewport/start URL shaping formanage_browsersand pools; list/get responses use compact summaries,next_actions, structuredssh_port_forwarding, and sharedpaginatedJsonResponse/itemsJsonResponsehelpers. MCP resources move tobrowser-pools://withregisterJsonResourceTemplatefor per-entity URIs; pagination and numeric tool inputs get stricter Zod bounds. Docs addbrowser_curland clipboard oncomputer_action.Reviewed by Cursor Bugbot for commit 6f3e4a7. Bugbot is set up for automated code reviews on this repo. Configure here.