Diwall MCP
Un serveur MCP qui donne à un modèle de langage la capture d'écran, l'arbre d'accessibilité et les gestes du navigateur où vous êtes connecté. Une fenêtre demande votre réponse avant une action irréversible, et un champ de mot de passe est masqué dans l'image et dans le texte.
Un modèle qui ne voit pas votre navigateur travaille à partir de votre description. Ce que vous omettez dans cette description, il l’ignore.
Avec Diwall MCP, il ouvre des pages dans un navigateur que vous avez choisi pour lui, reçoit la capture d’écran et l’arbre d’accessibilité que vous verriez, et agit dans les sessions où vous vous êtes connecté.
D’abord, ce que le modèle reçoit

Un appel à l’outil observe sur une page de connexion, sur un Raspberry Pi 4 (ARM 64 bits), dans un Chromium lancé pour le serveur
sur un profil à lui. Rien n’a été
saisi : le champ de mot de passe est vide, et le serveur le recouvre quand même
dans l’image.
L’image est celle que observe rend au modèle : chaque élément qu’il peut toucher
est dans un cadre numéroté, et le champ de mot de passe est recouvert d’un
rectangle plein.
Le texte que le modèle reçoit, clés omises, nom de l’application et nom du poste remplacés par des points de suspension, rien d’autre de modifié :
{"ok": true,
"server": {"capture": "ok",
"counters": {"marks": 3, "tree_lines": 10, "redacted_fields": 0,
"frames_masked": 0, "marks_truncated": false}},
"page_content": {"title": "… — Connexion",
"tree": ["RootWebArea \"… — Connexion\"",
" StaticText \"…\"",
" StaticText \"Interface d'administration\"",
" form \"\"",
" StaticText \"Identifiant\"",
" textbox \"Identifiant\"",
" StaticText \"Mot de passe\"",
" textbox \"Mot de passe\"",
" button \"Se connecter\"",
" StaticText \"…\""],
"elements": [{"mark": 1, "role": "textbox", "name": "Identifiant", "value": "",
"state": ["focused", "required"]},
{"mark": 2, "role": "textbox", "name": "Mot de passe", "value": "",
"state": ["required"]},
{"mark": 3, "role": "button", "name": "Se connecter", "value": ""}]}}
Omis : sous server, les clés origin, notices, tab_id, snapshot_id,
loader_id, viewport, dialog_open, image, operation_id et tool, et
les compteurs omitted_not_visible et tree_truncated ; sous page_content,
url ; dans chaque élément, in_viewport. Le champ de mot de passe ne contient
rien, la réponse n’a donc aucune valeur à son sujet. Un appel du même genre se
rejoue sur la page de démonstration du dépôt, docs/demo/index.html : le test
de fumée le fait sur votre machine : Installer et vérifier →
Ce que c’est
Diwall MCP donne à votre modèle les yeux et les mains d’une personne assise devant votre navigateur, dans vos propres sessions.
Votre client MCP lance le serveur et lui parle par l’entrée et la sortie
standard ; le modèle reçoit quatorze outils. Le serveur se rattache au navigateur
que vous lancez vous-même, sur un profil qui lui est
réservé, avec son port de débogage sur 127.0.0.1. Le modèle observe un onglet,
désigne un élément par son repère, et le serveur vérifie que l’élément est
toujours celui qui a été observé avant de cliquer ou de saisir.
Trois règles ne dépendent pas de ce que décide le modèle. Le serveur ne lit et n’agit que sur les sites que votre politique d’origines admet : par défaut, ceux que liste votre profil. Un paiement, une suppression irréversible ou un changement de secret attend votre réponse dans une fenêtre que le serveur ouvre sur votre écran. Un mot de passe est saisi depuis votre répertoire chiffré et n’atteint jamais le modèle. Ce qu’il ne fait jamais →
mcp-server-diwall-browser, en
Python 3.12 ou plus récent ; il s'installe depuis un paquet ou depuis un clone
du dépôt.Une session, de l’observation à une fenêtre de confirmation
→ observe {"tab_id": "f395445606543e95"} capture: ok — marks: 4 — redacted_fields: 1 [1] textbox "User name" [2] textbox "Password" [3] button "Sign in" [4] link "Help" → click {"snapshot_id": "56f18791c433fa584ea5067f99185355", "mark": 3} → click {"snapshot_id": "…", "mark": …} Confirmation du serveur MCP Origine : https://shop.example.invalid Outil : click — geste : clic Texte tiré de la page : button "Payer maintenant" Cible du formulaire : https://shop.example.invalid Montants détectés (heuristique) : 42,00 € Catégories : paiement Signaux : vocabulary_payment, card_field_on_page, card_field_in_form [ Autoriser ] [ Refuser ]
Le modèle ne vise pas des pixels : il désigne le repère 3, lié au bouton que le navigateur tient derrière lui. Si la page a déplacé ou remplacé ce bouton depuis l’observation, le clic est refusé et le modèle observe de nouveau. Le second clic vise un bouton de paiement : le serveur ne le fait qu’une fois votre accord donné, et rien ne se passe tant que vous n’avez pas répondu, dans une fenêtre qui appartient au serveur, pas au client du modèle. Quatre-vingt-dix secondes sans réponse valent un refus.
Le premier appel est l’observation réelle ci-dessus, abrégée à ses repères. Le
clic sur Sign in n’en montre que l’appel. La fenêtre appartient à une autre
page : c’est le texte que le serveur a construit dans la session du projet pour
un clic sur un bouton de paiement, à une adresse d’exemple
(section 9 du guide de l’opérateur) ;
ses libellés sont en français, tels que le serveur les écrit. Ce clic ne nomme
aucun intent_category : le verrou a été armé par les mots et les champs de
carte de la page, la ligne Signaux.
Où aller ensuite
- Guides : d’un clone du dépôt à un modèle qui travaille dans votre navigateur, en cinq étapes, chacune avec sa vérification.
- Perception : ce que contient une observation, et comment un repère est vérifié avant un clic.
- Cas d’usage : les outils dans l’ordre d’une tâche, dans une session où vous êtes déjà connecté, et ce que le projet a exécuté jusqu’ici.
- Architecture : ce qui quitte votre machine, les choix faits, les limites.
- Agents : si vous êtes un modèle de langage, commencez ici.
- Le projet : d’où il vient, son lien avec Diwall, qui l’a construit.