Skip to content

fix(browser): fix DOMShell MCP parameter mismatches and connection model#135

Merged
zhangxilong-43 merged 2 commits intoHKUDS:mainfrom
apireno:fix/browser-harness-domshell-compat
Mar 24, 2026
Merged

fix(browser): fix DOMShell MCP parameter mismatches and connection model#135
zhangxilong-43 merged 2 commits intoHKUDS:mainfrom
apireno:fix/browser-harness-domshell-compat

Conversation

@apireno
Copy link
Copy Markdown
Contributor

@apireno apireno commented Mar 23, 2026

Summary

  • 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 #118.

Type of Change

  • New Software CLI — adds a CLI harness for a new application
  • New Feature — adds new functionality to an existing harness or the plugin
  • Bug Fix — fixes incorrect behavior
  • Documentation — updates docs only
  • Other — please describe:

For Existing CLI Modifications

  • All unit tests pass: python3 -m pytest cli_anything/browser/tests/test_core.py -v
  • All E2E tests pass: python3 -m pytest cli_anything/browser/tests/test_full_e2e.py -v
  • No test regressions — no previously passing tests were removed or weakened
  • registry.json entry is updated if version, description, or requirements changed

General Checklist

  • Code follows existing patterns and conventions
  • --json flag is supported on any new commands
  • Commit messages follow the conventional format (feat:, fix:, docs:, test:)
  • I have tested my changes locally

Test Results

============================= 31 passed in 0.23s ==============================
cli_anything/browser/tests/test_full_e2e.py::TestDependencyChecks::test_cli_starts_when_domshell_available PASSED [ 10%]
cli_anything/browser/tests/test_full_e2e.py::TestPageCommands::test_page_info_empty PASSED [ 20%]
cli_anything/browser/tests/test_full_e2e.py::TestFilesystemCommands::test_fs_pwd PASSED [ 30%]
cli_anything/browser/tests/test_full_e2e.py::TestSessionCommands::test_session_status PASSED [ 40%]
cli_anything/browser/tests/test_full_e2e.py::TestDaemonMode::test_daemon_lifecycle PASSED [ 50%]
cli_anything/browser/tests/test_full_e2e.py::TestDaemonMode::test_daemon_start_with_json PASSED [ 60%]
cli_anything/browser/tests/test_full_e2e.py::TestErrorHandling::test_invalid_path_gives_error PASSED [ 70%]
cli_anything/browser/tests/test_full_e2e.py::TestErrorHandling::test_empty_page_info PASSED [ 80%]
cli_anything/browser/tests/test_full_e2e.py::TestJSONOutput::test_json_output_is_valid PASSED [ 90%]
cli_anything/browser/tests/test_full_e2e.py::TestCleanup::test_stop_daemon_if_running PASSED [100%]
======================== 10 passed, 1 warning in 7.35s =========================

🤖 Generated with Claude Code

- 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>
Copilot AI review requested due to automatic review settings March 23, 2026 20:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-proxy and add support for DOMSHELL_TOKEN / DOMSHELL_PORT.
  • Update MCP tool argument keys (ls, cat, click) and adjust type_text to focus+type in a single MCP session.
  • Remove forwarding of an unsupported path argument for grep (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.

Comment on lines +30 to +34
"-p", "@apireno/domshell",
"domshell-proxy",
"--port", os.environ.get("DOMSHELL_PORT", "3001"),
"--token", os.environ.get("DOMSHELL_TOKEN", ""),
]
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines 286 to 289
result = asyncio.run(_call_tool(
"domshell_grep",
{"pattern": pattern, "path": path},
{"pattern": pattern},
use_daemon
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
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)
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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)

Copilot uses AI. Check for mistakes.
- 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>
@yuh-yang
Copy link
Copy Markdown
Collaborator

mentioned at #118 (comment), mainly DOMShell-relevant issues

@yuh-yang
Copy link
Copy Markdown
Collaborator

This is a bugfix. The 3 issues are:

  1. Port conflict in one-shot mode
  2. MCP tool parameter name mismatches
  3. No --allow-write flag for write commands

This PR LGTM by addressing the above 3 issues.

Copy link
Copy Markdown
Collaborator

@zhangxilong-43 zhangxilong-43 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • No significant changes were found in the files
  • All E2E test cases passed

@zhangxilong-43 zhangxilong-43 merged commit a5aee5f into HKUDS:main Mar 24, 2026
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.

4 participants