Skip to content

fix(extension): Keep WebMCP responses that arrive before invokeTool resolves - #3233

Open
anishanne wants to merge 2 commits into
browserbase:mainfrom
anishanne:fix/webmcp-early-tool-responses
Open

anishanne wants to merge 2 commits into
browserbase:mainfrom
anishanne:fix/webmcp-early-tool-responses

Conversation

@anishanne

@anishanne anishanne commented Oct 19, 2026 •

Copy link
Copy Markdown

why

Fixes #2724.

WebMCP.toolResponded can arrive before the WebMCP.invokeTool command response reveals its invocation ID. The listener currently drops that event because the invocation has not been registered yet, leaving waitForWebMCPInvocationResult() pending indefinitely or until its timeout.

what changed

  • Responses for invocation IDs we don't know yet are held on the session's existing response state while an invokeTool command is in flight on that session.
  • When the command resolves, a held response for the returned ID settles the new record through the same path as a normally ordered response, including retention. The first response wins.
  • The buffer only lives while a command is pending. It is cleared when the last command finishes, including on failure, and when the session is detached or the page is disposed.
  • Changeset for the extension and SDK patches, and the Go SDK's embedded extension is regenerated.

Related: #2727 and #2887 address the same race condition. This implementation reuses the existing per-session response state and pending-command count, clearing unclaimed responses when the last pending command finishes or the session is torn down.

test plan

  • New cases emit toolResponded from inside the fake invokeTool handler, which is the ordering from the issue: early Completed, Canceled and Error responses; duplicates before and after registration; concurrent commands resolving in reverse order; isolation between sessions; stale responses not claimed by a later invocation; the failed-command path; retention; detach and dispose mid-command.
  • The early-response regression tests fail against main (c6b6f27) and pass with this change. Additional coverage checks session isolation, duplicate responses, cleanup, and retention. All 29 invocation lifecycle tests pass.
  • Extension unit suite (1,012 passed, 9 existing todos), typecheck, oxlint, oxfmt and changeset status pass.
  • Extension build and the Go SDK's embedded archive --check pass, and the extensionassets and extensionpack Go tests pass.

…esolves

CDP can deliver WebMCP.toolResponded before the response to the
WebMCP.invokeTool command that started it. The invocation record was
only created after the command resolved, so the early event was dropped
and waitForWebMCPInvocationResult() hung, or timed out.

Hold responses for unknown invocation IDs on the session's response
state while an invokeTool command is in flight, settle the new record
from the held response when the command resolves, and clear the buffer
once nothing is pending or the session is torn down so it stays bounded.

Fixes browserbase#2724
@changeset-bot

changeset-bot Bot commented Oct 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9940360

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 24 packages
Name Type
@browserbasehq/stagehand-extension Patch
@browserbasehq/stagehand-go Patch
@browserbasehq/stagehand Patch
@browserbasehq/stagehand-python Patch
browse Patch
@browserbasehq/stagehand-examples Patch
@browserbasehq/stagehand-integrations-claude-cua-sdk Patch
@browserbasehq/stagehand-integrations Patch
@browserbasehq/eve Patch
@browserbasehq/stagehand-integrations-gemini-cua-sdk Patch
@browserbasehq/stagehand-integrations-example-pi-facade Patch
@browserbasehq/stagehand-integrations-claude-agent-sdk Patch
@browserbasehq/stagehand-integrations-example-claude-code-facade Patch
@browserbasehq/stagehand-integrations-codex-sdk Patch
@browserbasehq/stagehand-integrations-example-codex-facade Patch
@browserbasehq/stagehand-integrations-cursor-sdk Patch
@browserbasehq/stagehand-integrations-example-cursor-facade Patch
@browserbasehq/stagehand-integrations-deepagents-sdk Patch
@browserbasehq/stagehand-integrations-eve-sdk Patch
@browserbasehq/stagehand-integrations-fx-sdk Patch
@browserbasehq/stagehand-integrations-mastra-sdk Patch
@browserbasehq/stagehand-integrations-example-mastra-facade Patch
@browserbasehq/stagehand-integrations-pi-sdk Patch
@browserbasehq/stagehand-integrations-example-vercel-ai-facade Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

Copy link
Copy Markdown
Contributor

This PR is from an external contributor and must be approved by a stagehand team member with write access before CI can run.
Approving the latest commit mirrors it into an internal PR owned by the approver.
If new commits are pushed later, the internal PR stays open but is marked stale until someone approves the latest external commit and refreshes it.

@github-actions github-actions Bot added external-contributor Tracks PRs mirrored from external contributor forks. external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. labels Oct 19, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. external-contributor Tracks PRs mirrored from external contributor forks.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WebMCP completion can be lost when toolResponded arrives before invokeTool resolves

1 participant