Skip to content

Fail WebMCP invocations fast when their document is replaced without a result - #498

Open
rgarcia wants to merge 1 commit into
mainfrom
hypeship/webmcp-fail-fast-on-reload
Open

rgarcia wants to merge 1 commit into
mainfrom
hypeship/webmcp-fail-fast-on-reload

Conversation

@rgarcia

@rgarcia rgarcia commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

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.

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.

Change

  • 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), give it a 500ms grace and then fail the invocation with the existing ErrOutcomeUnknown (still returns 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. No API or error-code change.

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 in about 1s after.
  • The existing navigate-then-respond fixture now emits frameStoppedLoading before the late result, covering the grace window.
  • 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 package.
  • Drove a patched webmcpclient.Manager 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 outcome_unknown
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

Not included

  • A distinct error code (e.g. tool_page_unloaded) and a dispatched field need OpenAPI, API, and SDK changes; left for a follow-up.
  • A reload that commits in the short window between WebMCP.invokeTool dispatch and its response isn't tracked and still waits for the timeout.

Reviewed with sol-loop: 1 round with openai-codex/gpt-6.1-sol on extra-high reasoning. Sol verdict: approved.

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