fix(browser): fix DOMShell MCP parameter mismatches and connection model#135
Conversation
- Switch from `domshell` to `domshell-proxy` (stdio bridge) to match how MCP clients like Claude Desktop integrate with DOMShell - Add DOMSHELL_TOKEN / DOMSHELL_PORT env var support for auth - Fix MCP tool parameter names: ls (options), cat (name), click (name) - Remove unsupported path param from grep - Fix type_text to focus (domshell_focus) then type in single MCP session - Add --allow-write --no-confirm flags for write commands Fixes issues reported in PR HKUDS#118. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the Browser harness’s DOMShell MCP integration to match a “running server + stdio proxy” connection model, and aligns several MCP tool argument shapes with DOMShell’s current expectations.
Changes:
- Switch DOMShell invocation to
domshell-proxyand add support forDOMSHELL_TOKEN/DOMSHELL_PORT. - Update MCP tool argument keys (
ls,cat,click) and adjusttype_textto focus+type in a single MCP session. - Remove forwarding of an unsupported
pathargument forgrep(but some higher-level APIs still expose it).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| browser/agent-harness/cli_anything/browser/utils/domshell_backend.py | Updates server command/args, MCP tool call argument shapes, and implements focus+type in one session. |
| browser/agent-harness/cli_anything/browser/core/fs.py | Changes grep behavior to no longer pass a root path to the backend. |
| browser/agent-harness/cli_anything/browser/tests/test_core.py | Updates unit tests to reflect the new backend grep signature/behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "-p", "@apireno/domshell", | ||
| "domshell-proxy", | ||
| "--port", os.environ.get("DOMSHELL_PORT", "3001"), | ||
| "--token", os.environ.get("DOMSHELL_TOKEN", ""), | ||
| ] |
There was a problem hiding this comment.
DEFAULT_SERVER_ARGS reads DOMSHELL_PORT/DOMSHELL_TOKEN at import time and always passes --token even when the env var is unset (empty string). Since the comment states the token is required, this will fail later with a less actionable MCP error. Consider building the args list at call time (so late env var changes are honored), and either (a) validate DOMSHELL_TOKEN is non-empty with a clear error, or (b) omit the --token flag entirely when unset if the proxy supports unauthenticated mode.
| result = asyncio.run(_call_tool( | ||
| "domshell_grep", | ||
| {"pattern": pattern, "path": path}, | ||
| {"pattern": pattern}, | ||
| use_daemon |
There was a problem hiding this comment.
grep() now calls domshell_grep without a root path, but in non-daemon mode each call starts a fresh MCP session. If DOMShell’s grep is rooted at the server-side current directory, this risks always searching from the default (often /) rather than the CLI session’s working_dir. If DOMShell doesn’t accept a path arg, consider implementing rooting by issuing domshell_cd + domshell_grep within the same MCP session (similar to type_text), or make the behavior explicit in the CLI/docs.
| target_path = path if path else session.working_dir | ||
| use_daemon = session.daemon_mode | ||
| return backend.grep(pattern, target_path, use_daemon=use_daemon) | ||
| return backend.grep(pattern, use_daemon=use_daemon) |
There was a problem hiding this comment.
grep_elements() still exposes a path parameter (and the docstring describes it as the grep root), but the implementation no longer uses either path or session.working_dir when calling the backend. This makes the API/CLI misleading and can change behavior compared to ls/cat. Either remove the path argument end-to-end (CLI/help/docs/tests) or reintroduce rooting by doing a cd + grep within the same MCP session.
| return backend.grep(pattern, use_daemon=use_daemon) | |
| # Determine the root path for the search. If no path is provided, use the | |
| # session's current working directory, matching ls/cat behavior. | |
| target_path = path if path else session.working_dir | |
| # If we don't have a meaningful target path, just grep from the backend's | |
| # current working directory. | |
| if not target_path: | |
| return backend.grep(pattern, use_daemon=use_daemon) | |
| # Temporarily change the backend's working directory for this grep, without | |
| # mutating session.working_dir. This keeps the API contract that `path` | |
| # roots the search, while preserving the existing session state. | |
| original_path = session.working_dir | |
| cd_result = backend.cd(target_path, use_daemon=use_daemon) | |
| if isinstance(cd_result, dict) and "error" in cd_result: | |
| return cd_result | |
| try: | |
| return backend.grep(pattern, use_daemon=use_daemon) | |
| finally: | |
| # Best-effort restore of the original backend working directory. | |
| restore_path = original_path or "/" | |
| backend.cd(restore_path, use_daemon=use_daemon) |
- Build server args at call time so DOMSHELL_TOKEN/DOMSHELL_PORT env var changes are honored after import; raise clear error if token unset - Implement cd+grep+cd pattern in grep_elements() so the path parameter correctly roots the search at the requested subtree - Update grep_elements_with_path test to verify cd+grep+cd behavior Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
mentioned at #118 (comment), mainly DOMShell-relevant issues |
|
This is a bugfix. The 3 issues are:
This PR LGTM by addressing the above 3 issues. |
zhangxilong-43
left a comment
There was a problem hiding this comment.
- No significant changes were found in the files
- All E2E test cases passed
Summary
domshelltodomshell-proxy(stdio bridge) to match how MCP clients like Claude Desktop integrate with DOMShellDOMSHELL_TOKEN/DOMSHELL_PORTenv var support for authls(options),cat(name),click(name)pathparam fromgreptype_textto focus (domshell_focus) then type in single MCP session--allow-write --no-confirmflags for write commandsFixes issues reported in PR #118.
Type of Change
For Existing CLI Modifications
python3 -m pytest cli_anything/browser/tests/test_core.py -vpython3 -m pytest cli_anything/browser/tests/test_full_e2e.py -vregistry.jsonentry is updated if version, description, or requirements changedGeneral Checklist
--jsonflag is supported on any new commandsfeat:,fix:,docs:,test:)Test Results
🤖 Generated with Claude Code