Skip to content

fix(mcp): let callers control the wait time cap and the act diff size - #2746

Merged
Dani Akash (DaniAkash) merged 5 commits into
mainfrom
fix/mcp-cap-ergonomics
Sep 24, 2026
Merged

Dani Akash (DaniAkash) merged 5 commits into
mainfrom
fix/mcp-cap-ergonomics

Conversation

@DaniAkash

@DaniAkash Dani Akash (DaniAkash) commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Two neo MCP cap/clamp ergonomics fixes, applied to both tool implementations so every client gets them: the TS browser-mcp tools (the built-in agent path) and the Rust browseros-mcp crate that claw-server-rust serves to external MCP clients (Claude, Codex over MCP). The reporter's "Claude over MCP" hits the Rust path, so covering it is the point.

wait for="time" no longer silently under-waits (Fixes #2701)

A for="time" pause is just an abortable sleep that does no page work, but it was clamped to the 30s page-work polling cap that text/selector waits use. So wait for="time" value=75000 returned waited 30000ms with no signal, and a caller pacing a long in-page loop under-waited and re-polled.

Now the pure-time pause is decoupled from that cap: it is honored up to 90000ms, an explicit timeout still bounds it from above (a caller can cap a large or garbage value), and a value past the ceiling is rejected with an error that names the cap rather than being silently shortened. The ceiling sits below the tool-call budget so the documented maximum completes rather than racing the outer timeout. The text/selector 30s polling cap is unchanged.

act can now suppress or cap the post-action diff (Fixes #2700)

act unconditionally appended a full post-action accessibility diff. On a large page that is a full page dump on every action (thousands of tokens the calling agent mostly cannot use).

act now takes an optional diff control:

  • "full" (default): unchanged, the existing token-bounded diff with spill-to-file.
  • "summary": change counts only, no tree body.
  • "none": skip the diff entirely.
  • a number: cap the inline diff to that many characters, spilling the rest to a local file (mirrors the maxChars control on evaluate).

The capped branch preserves the URL-change notice, so a truncated post-navigation snapshot is never mistaken for an ordinary in-page diff. The default path is left unchanged, so the diff tool and default act readback are unaffected.

Skill

The browseros-neo skill documents the tools, and it lives in two synced copies (the repo-root copy and the resource embedded into claw-server-rust). Both now note the new act diff control.

Tests

  • TS: wait.test.ts, act.test.ts, and diff-format.test.ts cover the honored/rejected/bounded wait cases and the none/summary/maxChars/nav-notice diff cases.
  • Rust: crate tests cover resolve_time_wait_ms, the act diff mapping and untagged deserialization, and the summary/maxChars/nav-notice/truncation diff cases.

The job-handle ask (#2703) is a larger async-job feature tracked separately.

wait for="time" no longer silently clamps a pure-time pause to the 30s
page-work polling cap. A time pause does no page work, so it is honored
up to the tool-call budget (120000ms) and a larger value is rejected
naming the cap instead of quietly under-waiting.

act now takes a diff param ("none" | "summary" | "full" | maxChars,
default "full") so a caller can suppress or cap the auto-included
post-action accessibility diff, which otherwise dumps the whole page on
every act. Char-based cap mirrors the evaluate maxChars control.

Fixes #2701
Fixes #2700
@github-actions github-actions Bot added the fix label Sep 23, 2026
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

✅ Tests passed: 2368/2371

Ran 11 of 16 suites (5 not affected by this change).

Suite Passed Failed Skipped
✅ server-agent 207/207 0 0
✅ server-api 274/274 0 0
✅ server-tools 248/248 0 0
✅ server-browser 10/10 0 0
✅ server-integration 10/10 0 0
✅ server-lib 200/200 0 0
✅ server-root 38/41 0 3
✅ agent 463/463 0 0
⏩ claw-app n/a n/a not affected
⏩ claw-onboard n/a n/a not affected
⏩ app-onboard n/a n/a not affected
⏩ build n/a n/a not affected
⏩ release n/a n/a not affected
✅ claw-server-rust 783/783 0 0
✅ claw-server-rust-quality passed 0 0
✅ claw-mcp 135/135 0 0

passed = ran successfully but emits no JUnit counts (a lint/format gate).

View workflow run

@greptile-apps

greptile-apps Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge; the previously reported timeout-budget and navigation-labeling issues are resolved, and no new actionable issue was found.

Summary

This PR aligns the TypeScript and Rust MCP implementations so callers can control long time waits and post-action diff size.

  • Allows pure time waits up to 90 seconds while retaining explicit caller-provided timeout bounds.
  • Adds full, summary, none, and character-capped post-action diff modes.
  • Preserves URL-change context and untrusted-content wrapping in capped diff output.
  • Updates both BrowserOS neo skill copies and MCP guidance.
  • Adds coverage for wait limits, mode mapping, truncation, spill-to-file behavior, and navigation notices.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    Caller[MCP caller] --> Act[act]
    Act --> Mode{diff option}
    Mode -->|full or omitted| Full[Token-bounded full diff]
    Mode -->|summary| Summary[Change counts only]
    Mode -->|none| None[Skip post-action diff]
    Mode -->|number| Cap[Character-capped excerpt]
    Cap --> Spill[Spill full marked diff to output file]
    Caller --> Wait[wait for=time]
    Wait --> Bound[Apply explicit timeout bound]
    Bound --> Cap90[Reject resolved waits above 90000ms]
Loading

Reviews (3) · Last reviewed commit: "docs(mcp): note the act diff control in ..."

Comment thread packages/browseros-agent/packages/browser-mcp/src/tools/wait.ts Outdated
wait for="time": keep an explicit timeout as an upper bound on the pause
(restores the documented bound the first pass dropped) while still lifting
the 30s page-work clamp, and hold the pure-time ceiling below the tool-call
budget so the documented maximum completes rather than racing the outer
timeout.

act diff: preserve the URL-change notice when a maxChars-capped readback is
actually the new page's snapshot after a navigation, so a truncated snapshot
never reads as an ordinary in-page diff.
…st tools

The rust crate that claw-server-rust serves to external MCP clients (Claude,
Codex over MCP) carried the same two issues as the TS tools: wait for="time"
silently clamped a pure pause to the 30s page-work cap, and act always dumped
the full post-action diff. Port both fixes so an external client gets the same
behavior as the built-in agent.

wait for="time" is honored up to 90000ms with an explicit timeout as an
optional upper bound; a larger value is rejected naming the cap. act takes a
diff control ("none" | "summary" | "full" | a character cap) and skips the
readback for "none", and the capped branch keeps the URL-change notice.

Update the browseros-neo skill in both copies (the repo-root copy and the
resource embedded into the server) to document the act diff control.
@DaniAkash Dani Akash (DaniAkash) changed the title fix(browser-mcp): let callers control the wait time cap and the act diff size fix(mcp): let callers control the wait time cap and the act diff size Sep 24, 2026
@DaniAkash

Copy link
Copy Markdown
Contributor Author

Greptile (@greptileai)

The crate's fallback instructions (browseros-mcp service) and the production
claw-server instructions both carry the act guidance line that the neo skill
carries; keep them consistent with the new act diff control.
@DaniAkash

Copy link
Copy Markdown
Contributor Author

Greptile (@greptileai)

@DaniAkash
Dani Akash (DaniAkash) merged commit 68d6e9b into main Sep 24, 2026
22 checks passed
@DaniAkash
Dani Akash (DaniAkash) deleted the fix/mcp-cap-ergonomics branch September 24, 2026 11:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

1 participant