Diwall MCP

English
Download v0.0.1

Technical choices

A DevTools client written by hand with 27 allowed methods, standard streams instead of a port, a confirmation window the model's client cannot answer, and the options set aside with what would reopen them.

Python, four pinned dependencies

The server is a Python package (3.12 or later). Its runtime dependencies are pinned to exact versions in pyproject.toml: mcp 1.25.0 (the MCP SDK), websockets 15.0.1, pillow 12.0.0 and pydantic 2.12.5. There is no browser automation library among them.

A DevTools client written by hand

With a general automation library, what the server can send to the browser is whatever the library can send. The server has its own client for the Chrome DevTools Protocol instead, and the methods it may call are a list of 27, in one module; a test compares that list with every method name the code uses. Scripts reach a page only from a table of constant texts in that module. The arguments of a tool travel in the protocol’s arguments field and are never written into a script, so a value the model chooses cannot become code.

Standard streams, no port

The server talks to its client over standard input and output and holds no listening socket. A listening port can be reached by any process of the machine; standard streams tie the server to the one client that started it. It runs with a core file limit of zero and writes nothing but the protocol on its standard output.

A confirmation the client cannot answer

The MCP client acts for the model, and may answer a request by itself. So a payment, an irreversible deletion or a change of secret is confirmed in a window the server opens with kdialog or zenity, started without a shell, that shows the state read in the browser at that moment: the origin, the gesture, the text of the element, the target of the form, the amounts found. Refusal is the default button where the window program allows it; no answer within 90 seconds counts as a refusal. One answer covers one action. The one exception, a request through the client (elicitation), needs a declaration of your operator profile.

What arms the lock is a vocabulary written in the code and the card fields of the page. The model’s intent_category and the page heuristics can add a lock; nothing removes one, and the operator profile cannot configure them.

Set aside, and what would reopen it

  • Playwright or a similar library. What the server sends would be the library’s list, not the project’s. Would reopen it: a browser whose protocol the hand-written client can no longer speak.
  • A tool that runs a script. It would bypass marks, identity checks, the lock and the masks, and read anything a page holds. Would reopen it: a task of yours the tools cannot do, then as a new constant script, never one the model writes.
  • Reading inside frames. A frame of another origin is another site, often a payment or an advertising one. Would reopen it: a site of your list whose needed content sits in a frame of the same origin.
  • A network transport. A listening port is reachable by any local process. Would reopen it: a client you need that reaches servers over the network only.
  • Higher caps. They keep what the model receives bounded. Would reopen it: a page whose only layer is cut under the present order.
  • A tool that converts credentials. The model would be handed the path of a file of secrets. Would reopen it: an operator with no shell, and a way to keep the values out of the model’s session.
  • A browser context of the server’s own. Its tabs would not share your signed-in sessions, the reason for the project. Would reopen it: a browser that accepts the download setting for one tab alone.

Diwall, the project this one descends from, also gives a model an image with numbered elements and the accessibility tree; its browser and its transport are not these. How the two projects relate is on The project.