Repository navigation
Conversation
Contributor
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
Contributor
Author
|
Picked tnsardesai to review these related PRs (kernel/kernel-images#498, kernel/kernel#5165): touched the changed code in |
rgarcia
added a commit
to kernel/kernel-images
that referenced
this pull request
Nov 1, 2026
…is replaced (#498) ## Summary When the document that owns a pending WebMCP invocation is reloaded or navigated by anything other than the tool itself, `POST /webmcp/invoke` waits out the full `timeout_sec` (up to 120s) before returning `outcome_unknown`, even though no result can ever arrive. This fails those invocations fast with a distinct `410 tool_page_unloaded`, and marks both invoke failures that may have had side effects as non-retryable for SDKs. Chromium only answers a pending invocation across a navigation when the tool started that navigation (`WebMCPHandler::DidFinishNavigation` checks `GetScriptToolInvocationId()`): cross-origin gets an immediate `Error`, same-origin gets a result from the new document around its `DOMContentLoaded`. A reload or navigation from Playwright, the user, or unrelated page script never produces `WebMCP.toolResponded`. `webmcpclient` dropped the frame's tools on a document change but kept the invocation waiting. ## Changes **Fail fast** (`lib/webmcpclient`) - Mark a waiting invocation when its frame commits a new document (`EventDocumentChanged`). - When that replacement document finishes loading (`Page.frameStoppedLoading` on the same session and frame), wait 500ms more, then fail the invocation with `ErrToolPageUnloaded` (keeps `invocation_id`). - Waiting for the replacement load rather than a fixed delay after commit keeps tool-initiated navigations working: their result can arrive seconds after commit on slow pages, but always before the load finishes. **Renderer crashes** (`lib/webmcpclient`) - Chrome keeps a crashed tab open, so its tools stayed in discovery. Invoking one hung for the full `timeout_sec` (the `WebMCP.invokeTool` command to a dead renderer never answers), and an invocation pending at crash time also waited out the timeout. - On `Inspector.targetCrashed`, drop that session's tools and fail its pending invocations with `ErrToolPageUnloaded` after the same 500ms grace. The session stays enabled, so tools registered after the tab is reloaded or navigated are picked up. - A recovery reload right after the crash keeps the crash deadline. **API** (`cmd/api/api/webmcp.go`, `openapi.yaml`, regenerated `lib/oapi/oapi.go`) - `ErrToolPageUnloaded` → `410` with `code: "tool_page_unloaded"`, `message`, and `invocation_id`. - `410 tool_page_unloaded` and the existing `504 outcome_unknown` both set `X-Should-Retry: false`. Kernel SDKs retry 408/409/429/5xx by default unless that header says otherwise, so a default-configured client could re-invoke a tool after a 504 even though it may already have run. 410 isn't retried by the SDKs even without the header. Both headers are declared in the spec. - `410` reports a known cause, not a known outcome: the tool may have had side effects before its page went away, so callers must not retry it automatically. - REPL help (`webmcp.invokeTool`) and `docs/repl.md` mention the new code. ## Deploy order kernel/kernel#5165 must deploy first. Until metro-api allows the new code, its `/browser/kernel` passthrough rewrites `410 tool_page_unloaded` to `session_gone`. That PR also adds the header and 410 passthrough on the control-plane path. Docs: kernel/docs#738. ## Tests - New regression fixture `reloadWithoutResult` in the fake CDP server replays the event sequence observed from Chromium for an external reload (`frameStartedLoading` → `frameNavigated` → `frameStoppedLoading`, no `toolResponded`). `TestInvocationFailsFastWhenToolDocumentReloadsWithoutResult` waited the full 10s before this change and returns `ErrToolPageUnloaded` in about 1s after. - The existing navigate-then-respond fixture now emits `frameStoppedLoading` before the late result, covering the grace window. - `TestInvocationFailsFastWhenToolRendererCrashes` (crash while pending, tools removed, stale ref returns `ErrToolNotFound`) and `TestInvocationFailsFastWhenCrashedToolPageReloads` (crash, then a recovery commit that never finishes loading) both waited the full 10s before the fix. - Handler tests check status, `X-Should-Retry`, and body for both the 504 and the 410. - `go vet` clean; `go test -race` passes for all non-e2e packages except `lib/devtoolsproxy` `TestUpstreamManagerDetectsChromiumAndRestart`, which fails the same way on `main` in my environment (temp dir cleanup with local Chromium) and doesn't depend on this change. - Drove a `webmcpclient.Manager` with the fail-fast change against a production Chromium 155 browser over CDP (20s timeout): | scenario | before | after | |---|---|---| | external reload / `Page.navigate` / page-script reload | 20.0s `outcome_unknown` | 1.9–2.3s, invocation failed | | tool reloads its own page | `Completed` with output | `Completed` with output | | tool navigates cross-origin | Chromium `Error` | Chromium `Error` | | no navigation | 20s timeout | 20s timeout | Renderer crash via CDP `Page.crash` (15s timeout): | scenario | before | after | |---|---|---| | invocation pending when the tab crashes | 15.0s `outcome_unknown` | 1.7s `tool_page_unloaded` | | tools listed after the crash | crashed tab's tools | none | | invoke a crashed tab's tool ref | 15.0s `outcome_unknown` | immediate 404 | | navigate the crashed tab, register, invoke ×3 | ~0.02s each | ~0.02s each | ## Not included - A `dispatched` field on failures. - A reload or crash in the short window between `WebMCP.invokeTool` dispatch and its response isn't tracked and still waits for the timeout. Reviewed with sol-loop: 5 rounds with openai-codex/gpt-6.1-sol on extra-high reasoning. Sol verdict: approved. --------- Co-authored-by: rgarcia <72655+rgarcia@users.noreply.github.com>
rgarcia
added a commit
to kernel/kernel-images
that referenced
this pull request
Nov 2, 2026
## Summary Raises the `POST /webmcp/invoke` input limit from 1 MiB to 4 MiB after JSON serialization, with the request body cap moving to 4 MiB plus the existing 4 KiB envelope allowance. MCP clients commonly allow 4 MiB tool calls, so agents send inputs (for example images as `data:` URLs) that the old limit rejected. - `maxWebMCPInputBytes` goes to `4 << 20`; `maxWebMCPRequestBytes` and the request-size middleware follow it. - The 400 message and the spec descriptions (`WebMCPInvokeRequest.input` and the request body) say 4 MiB; `lib/oapi/oapi.go` regenerated (embedded spec only). - Tool output limits are unchanged. Chromium handles larger inputs: `WebMCP.invokeTool` with 1.5, 4, 8, and 16 MiB string inputs completed on a production browser over metro's CDP proxy (4 MiB in about 0.6s). ## Rollout The public API checks the same limit, so kernel/kernel#5165 raises it there. Ship this image before the API change reaches production; until then, browsers on older images reject inputs over 1 MiB with a 400. Docs: kernel/docs#738. ## Tests - New `TestInvokeWebMCPToolAcceptsInputAboveOneMiB` (2 MiB input reaches the client). - Existing oversized-input and middleware tests use the constants, so they now check the 4 MiB boundary. - `go test ./cmd/api/api/ -run WebMCP` passes; `go vet` clean. Co-authored-by: rgarcia <72655+rgarcia@users.noreply.github.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Documents the new WebMCP invoke failure
tool_page_unloaded(HTTP 410) and theX-Should-Retry: falseheader on it and onoutcome_unknown.Tool reference lifecycle: navigation after an invocation begins still returns a result when the tool starts it. If something else reloads or navigates the page first, the API returns
tool_page_unloadedonce the new page loads instead of waiting fortimeout_sec.Handle an unknown outcome: points to the new code and notes the header, while keeping the advice to disable SDK retries so transport failures aren't retried either.
New "Tool page unloaded" subsection: example body, what the code does and doesn't tell you (the tool may still have had side effects), and what to do next.
Tab crashes: a crash also returns
tool_page_unloaded, the crashed tab's tools disappear from discovery and their references return404, and Kernel doesn't replace a crashed tab.Input limit: the invoke input limit is now 4 MiB (was 1 MiB), with a 4 MiB plus 4 KiB request body.
Merge after
Merge once kernel/kernel#5165, kernel/kernel-images#498, and kernel/kernel-images#500 are deployed and a browser image with the change is live.
Reviewed with sol-loop: 5 rounds with openai-codex/gpt-6.1-sol on extra-high reasoning. Sol verdict: approved.