ShellRS
ShellRS 是一款免費、開源的 SSH 客戶端,使用 Rust 編寫:主機管理、終端機、WinSCP 風格的 SFTP 與埠轉發,全部於一個 GPU 渲染視窗中,支援 macOS、Windows 與 Linux。
AI 翻譯
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Diwall MCP — the operator's browser, seen and handled by a language model. An MCP server that gives the model the screenshot, the accessibility tree and the gestures of the browser where the operator is signed in, under their confirmation.
翻譯準備中
正在載入完整 README。
檢視完整 README ↗English | Français | Deutsch | Español
https://github.com/user-attachments/assets/2e7f579f-5466-4bb2-b78d-9c617ebdbfc9
An MCP server that gives a language model the eyes and hands of an operator in the operator's own browser, through the Chrome DevTools Protocol: the model sees the same screenshot and the same accessibility tree as the operator, and acts in the same authenticated session. It needs a Chromium-family browser that the operator starts with a dedicated profile and a debugging port bound to the loopback interface, and an encrypted directory (gocryptfs) for credentials, captures, downloads and the files the model may attach to a form.
The server does not work without an encrypted directory: the profile of the browser it attaches to keeps your
signed-in sessions, and they must not sit on the disk in clear. There is no mode without encryption. After
installing, the first command, which you run yourself in a terminal, is mcp-server-diwall-browser-setup: it
reads your machine and ends on the next command to type.
mcp-server-diwall-browser-setup create --temporary makes a volume in memory, for a trial. Closing it, stopping
the machine or ending your session destroys it, and with it the sessions of the sites you opened in the
browser, the audit journal and the evidence.mcp-server-diwall-browser-setup create makes a durable volume.mcp-server-diwall-browser-setup open, browser and close open the volume, start the browser on its profile,
and stop both.You type the password yourself, at the prompt of gocryptfs; the assistant never reads it. You sign in to your sites
yourself, in the browser it starts. After adding the server to your MCP client, restart the client: a session
that was already open does not see it. The steps, the refusals and the manual way are in the section "First launch" of
docs/OPERATOR_GUIDE.md.
The list of sites in the operator profile bounds what the model reads and acts on, never where it navigates. The key
origin_policy chooses what the server does with an origin that the list does not hold:
strict (the default, also when the key is missing): the origin is refused, and only the origin is returned.discovery: the server asks you in a window, once per origin: Refuser (the default answer), Cette séance or
Ajouter à la liste, which writes that exact origin in your profile.open: every public site is read and acted on, and its content goes to the provider of the model; local addresses and
names stay on the list. It is the freest policy and the riskiest, and it is yours to choose.Payments, irreversible deletions and secret changes keep their confirmation, and a credential is typed only on the exact origin it is bound to, in the three policies. The details are in section 5 of docs/OPERATOR_GUIDE.md.
On Linux the server ships as native packages. Download the one of your system from the Releases page of the repository or from the install guide of the website, then install it from the folder that holds it:
| System | Command |
|---|---|
| Debian 13, Ubuntu 24.04 and 26.04 | sudo apt install ./mcp-server-diwall-browser_0.0.2-1_all.deb |
| Fedora 44 | sudo dnf install ./mcp-server-diwall-browser-0.0.2-1.fc44.noarch.rpm |
| openSUSE Leap 16.0 | sudo zypper install --allow-unsigned-rpm ./mcp-server-diwall-browser-0.0.2-1.leap160.noarch.rpm |
| Arch Linux | sudo pacman -U ./mcp-server-diwall-browser-0.0.2-1-any.pkg.tar.zst |
Installation, the start of the server by an ordinary account and removal are validated in containers on
these systems. A container shows neither the confirmation window, nor the mounting of the encrypted
directory, nor a browser. Debian 12 and Ubuntu 22.04 are not supported: their Python is older than 3.12.
The installation needs a network connection: the package creates a Python virtual environment and
installs the dependencies, at the versions the project tested. The manual page is man mcp-server-diwall-browser.
To install from a clone of the repository instead, follow docs/OPERATOR_GUIDE.md.
A 64-bit ARM machine takes the same .deb, since the package does not depend on the architecture: a Raspberry Pi 4 under Debian 13 was tried with the package of the first release (see "What is tested, what is not"). The browser there is the distribution's Chromium.
The server speaks MCP over standard input and output. With a package installed, the command is
mcp-server-diwall-browser and the operator profile is read from its standard place:
claude mcp add --scope user diwall-browser -- mcp-server-diwall-browser
From a clone of the repository, with Claude Code:
claude mcp add --scope user diwall-browser \
-e MCP_DIWALL_BROWSER_PROFILE="$HOME/.config/mcp-server-diwall-browser/profile.json" \
-- "$HOME/mcp-server-diwall-browser/.venv/bin/python" -m mcp_server_diwall_browser
For another MCP client, the generic mcpServers block. The client does not expand ~, so this
command prints the block with your home directory in the paths, ready to paste into its
configuration:
cat <<EOF
{
"mcpServers": {
"diwall-browser": {
"command": "$HOME/mcp-server-diwall-browser/.venv/bin/python",
"args": ["-m", "mcp_server_diwall_browser"],
"env": {
"MCP_DIWALL_BROWSER_PROFILE": "$HOME/.config/mcp-server-diwall-browser/profile.json"
}
}
}
}
EOF
Adapt ~/mcp-server-diwall-browser to where you cloned the repository, and the profile
path to where you wrote your operator profile. The variable can be left out when the operator
profile is at its standard place, ~/.config/mcp-server-diwall-browser/profile.json. The form of
the claude mcp add command was checked against claude mcp add --help, then run by the operator
on Debian: claude mcp list showed the server connected. The tests start the server exactly as
these two blocks do:
python -m mcp_server_diwall_browser with MCP_DIWALL_BROWSER_PROFILE set.
Everything that comes before (installing, starting the browser, opening the encrypted directory, writing the operator profile) is in docs/OPERATOR_GUIDE.md. How it works and why is in docs/ARCHITECTURE.md.
The image above was produced by scripts/smoke_test.py from the local demo page
(docs/demo/index.html). The numbered marks are drawn by the server: an action names an element
by its mark. The password field, which the page filled itself, is masked by a solid rectangle, and
its value is withheld from the text the model receives (redacted_fields is 1).
Tested:
requirements.lock: without a
browser, 2276 tests pass, 1 is skipped (a test that runs as root only) and the 632 that need a browser are
deselected; with Google Chrome 156.0.8078.79 (headless, blank temporary profile), 2908 tests pass and 1 is
skipped, with no expected failure.docs/JOURNAL.md.scripts/smoke_test.py returns 0 against Google Chrome 155.0.8059.84 and 3 when no browser is found..deb installed by apt; the first launch of the setup assistant end to end with the real gocryptfs (temporary and durable volumes, browser, close); scripts/smoke_test.py returning 0; the server driven through a real MCP client on a visible Chromium with a window, not headless, on a virtual X11 screen, with the native confirmation window of zenity opened and left to expire; then the package removed and purged, no file left. The complete suite there gave 2694 tests passed and 1 skipped in 15 minutes (five of them are measurements of that machine that the repository does not hold). On that network, the first page loaded by a freshly started Chromium took 15 to 26 seconds, which made three tests fail in a first run; with the browser cut off from the network, they all pass (guide, section 12).tests/test_scale_integration.py). Before the correction of this, a mask did not
cover its field at a scale above 1. A real screen at 1.5 was not measured.Not tested:
browser command with Brave, Chromium or Opera.docs/OPERATOR_GUIDE.md, section 7).Known limits:
confirm or a prompt dialog asks the operator in a window, whatever its message says.
Accepting a dialog whose message asks for a payment, a deletion or a secret change is always
refused: no capture can be taken while a dialog is open. The operator answers such a dialog.token, and the fragment, are redacted.overflow clipping, so text a
human cannot read can still reach the model.marks_truncated, tree_truncated).
Past that, the server keeps first what is in a layer above the page (a dialog, a modal node, a
fixed or sticky node painting over content in view, such as a cookie banner), listed under an
overlay line in the tree, then what is in view and clear, then what is in view under a layer
(covered: true, and a click on it is refused), then the rest. A banner that overlaps nothing in
view is not a layer and can still be cut.mcp-server-diwall-browser is built in an asymmetric human–LLM collaboration. The roles are written down as they were actually played; the full list is in CONTRIBUTORS.md.
sudo, mount, /proc).License: MIT, see LICENSE.
tests/test_zoom_integration.pytests/test_zoom_scrolled_integration.pycaptureokcaptureunavailabletests/test_perception_zoom.pyActions.click, with its gate and its limits); the test page counts what each of
its buttons receives and a separate session reads the counts. At each of the eight combinations a
button of 120 by 32 CSS pixels, a button of 16 by 16 between two decoys 4 pixels from it, a button two
and a half views down, and the large button after the page was scrolled to put it in the middle of the
view, each received exactly one click, no decoy received any and none fell outside a button. On a page
scrolled in both directions the click lands on the button put in the middle of the view, and a button
covered by a banner fixed to the view is refused (element_obscured) with nothing clicked
(tests/test_click_integration.py, 264 tests; tests/test_click_targets_page.py, 51, and
tests/test_click_lookup_point.py, 20, need no browser). The same check refuses a click sent to the
point of the box multiplied by the zoom, divided by it, or multiplied by the screen scale (64 of 64
such clicks reached no button), and a server that asks the browser about the point of the view. Before
the correction, 20 of the 32 attempts at the first page failed, those that needed a scroll, and a button
covered by the banner was accepted and the banner was clicked, at the eight combinations: the browser
answers the node lookup for a point of the document, and the click gave it a point of the view. The
measures are in docs/JOURNAL.md.element_obscured) with nothing clicked, and in the 24 attempts it is refused every time
(tests/test_click_shifting_integration.py, 80 tests; tests/test_click_shifting_page.py, 30, and
tests/test_click_moving_page.py, 10, need no browser). Before the change the same 24 attempts returned
no error and the click landed on the intruder. After a refusal, a click on a new observation lands.
The server now asks the browser again what lies under the point after the movement and before the press,
every time, so a target that is covered where it stands, by a button shown at the first movement, is
refused too (tests/test_click_covering_integration.py, 3 tests, on Chrome 154.0.8037.97). The 24
attempts above were measured on Chromium 141.0.7390.37. The measures, and those of a page that scrolls
without stopping, are in docs/JOURNAL.md.covered, and a click
on "Refuse" by its mark takes the banner away (tests/test_ranking_integration.py).mcp-server-diwall-browser-setup: 50 tests on a simulated machine (mount tables, package
managers, no /dev/fuse, no terminal, a LUKS volume); then, with the real gocryptfs 2.5.1 in a
pseudo-terminal, on throw-away volumes: create --temporary, the server reading mounted, browser
(Google Chrome 155.0.8059.84 without a screen, attached, profile_encrypted: true), close (no volume left in
memory, no file of the browser profile on the disk), then create, close and open of a durable volume; and
in a clean Debian 13 container, where check gave sudo apt install gocryptfs fuse3, which succeeded.status read mounted and profile_encrypted: true, and the server wrote
its journal and created downloads/ in it. Opera 136 (Chromium 152), started with its profile
in that volume and a debugging port on the loopback interface, was attached; the server opened
a page of a public shopping site, filled its search field, pressed Enter and observed the
results. The typed text does not appear in the journal.strict, discovery, open): tests/test_origin_policy.py and tests/test_origin_policy_server.py on a simulated browser, and tests/test_origin_policy_integration.py, 12 tests of the server started by its entry point against Google Chrome 155.0.8059.84, with fake window programs: a portal that links to a second origin, a redirection to an unknown origin, the three answers of the window (the profile read back after Ajouter à la liste), local names refused under open, a payment that still asks its window, and the policy changed in the profile without restarting. The windows of the real kdialog and zenity were shown in a virtual screen and answered by keystrokes (Enter and Escape give the refusal); a person answered them (the next entry).kdialog 25.04.0 and once with zenity 4.1.90 (the server found only that tool):
with each, a refusal returned confirmation_denied and the page received nothing; an acceptance made the
click and the page received one request; with no answer, the request expired after 90.4 seconds
(confirmation_expired) and the page received nothing. The journal holds one requested line and one
line with the outcome for each of the six requests.status through Claude Code read
confirmation_channel: native, so the display reached the server.