Serveur MCP de contrôle Android OmniWeb
Un serveur MCP qui encapsule le "middleware Android" d'OmniWeb (le service Flask omniweb-android, /api/android/*) afin qu'un client MCP — Claude Code, Claude Desktop, ou un client personnalisé — puisse contrôler les téléphones Android et les modems USB du laboratoire.
C'est un client HTTP léger sur l'API REST existante (il n'importe aucun interne de Flask), donc il fonctionne contre n'importe quelle instance omniweb-android accessible.
Outils exposés
| Outil | Signature | Ce qu'il fait |
|---|---|---|
list_devices | () | Tous les appareils connus (téléphones + modems), en ligne et hors ligne. |
device_info | (serial) | Détails complets pour un appareil. |
screenshot | (serial) → image PNG | Écran actuel (universel : téléphones scrcpy ET anciens appareils de capture d'écran). |
tap | (serial, x, y) | Tapoter aux coordonnées de pixels. |
swipe | (serial, x1, y1, x2, y2, ms=200) | Glisser/faire glisser/lancer. |
input_text | (serial, text) | Taper dans le champ focalisé. |
key | (serial, name) | Appuyer sur retour/accueil/récents/entrée/supprimer/alimentation/menu/volume_haut/volume_bas. |
adb_shell | (serial, command, timeout=30) → {stdout, stderr, return_code} | Commande adb shell arbitraire (outil puissant). |
list_scripts | () | La bibliothèque de scripts de test de l'appareil. |
run_script | (serials, file, params={}) | Exécuter un script sur plusieurs appareils ; renvoie des handles d'exécution. |
get_run | (run_id) | Résultat d'une exécution de script (statut/stdout/code_de_retour). |
at_command | (serial, command, read_ms=0, timeout_ms=0) | Commande AT brute à un modem USB. |
send_sms | (serial, number, text) | Envoyer un SMS depuis un modem. |
Configuration (variables d'environnement)
Cible du backend :
OMNIWEB_API_BASE— URL de base du service android. Par défauthttp://127.0.0.1:5002. Le préfixe/api/androidest ajouté automatiquement.
Authentification du backend (choisissez UN) :
OMNIWEB_JWT— un jeton d'accès backend pré-minté (Bearer), OUOMNIWEB_JWT_SECRET— laJWT_SECRET_KEYdu backend. Le serveur génère alors un JWT admin à durée de vie courte et le rafraîchit automatiquement.OMNIWEB_JWT_TTL(secondes, par défaut 3600) contrôle sa durée de vie.
La propre porte d'entrée de ce serveur MCP :
MCP_TRANSPORT—http(par défaut, HTTP streamable pour les clients distants) oustdio(localclaude mcp add).MCP_HOST/MCP_PORT— adresse de liaison pour le transport http. Par défaut127.0.0.1:5005.MCP_AUTH_TOKEN— jeton bearer qu'un client MCP distant doit présenter. Nécessaire pour se lier à autre chose que localhost — le serveur refuse une liaison non-loopback sans cela (échec fermé). Sur/mcp, le jeton est vérifié par le middleware ;/et/healthsont ouverts pour les vérifications de santé.
Exécution
venv (autonome)
cd /opt/omniweb-mcp # ou où que vous ayez mis server.py + requirements.txt
python3 -m venv venv
venv/bin/pip install -r requirements.txt
export OMNIWEB_API_BASE=http://127.0.0.1:5002
export OMNIWEB_JWT_SECRET=<la clé JWT_SECRET_KEY du backend>
export MCP_TRANSPORT=http
export MCP_HOST=0.0.0.0
export MCP_PORT=5005
export MCP_AUTH_TOKEN=<un long jeton aléatoire>
venv/bin/python server.py
systemd (production)
Une unité est fournie à packaging/omniweb-android-mcp.service. Elle lit /etc/omniweb/omniweb.env (pour JWT_SECRET_KEY → elle est ré-exportée en tant que OMNIWEB_JWT_SECRET, voir ci-dessous) ainsi que /etc/omniweb/android-mcp.env pour les secrets spécifiques à MCP. Créez ce fichier (chmod 600) :
# /etc/omniweb/android-mcp.env
OMNIWEB_JWT_SECRET=<même valeur que JWT_SECRET_KEY dans omniweb.env>
MCP_AUTH_TOKEN=<un long jeton aléatoire>
Ensuite :
sudo cp packaging/omniweb-android-mcp.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now omniweb-android-mcp
Le fichier d'environnement du backend nomme le secret JWT
JWT_SECRET_KEY; ce serveur litOMNIWEB_JWT_SECRET. DéfinissezOMNIWEB_JWT_SECRETexplicitement dansandroid-mcp.env(copiez la valeur) afin que les noms correspondent.
Connexion depuis Claude Code
Distant (HTTP streamable), avec authentification :
claude mcp add --transport http android-control http://<host>:5005/mcp \
--header "Authorization: Bearer <MCP_AUTH_TOKEN>"
Local (stdio), pointant le serveur vers un backend et générant son propre JWT :
claude mcp add android-control \
-e OMNIWEB_API_BASE=http://127.0.0.1:5002 \
-e OMNIWEB_JWT_SECRET=<clé JWT_SECRET_KEY du backend> \
-e MCP_TRANSPORT=stdio \
-- /opt/omniweb-mcp/venv/bin/python /opt/omniweb-mcp/server.py
Ensuite dans Claude Code : /mcp pour confirmer la connexion, et essayez list_devices.
Connexion depuis Claude Desktop
claude_desktop_config.json — lancement stdio :
{
"mcpServers": {
"android-control": {
"command": "/opt/omniweb-mcp/venv/bin/python",
"args": ["/opt/omniweb-mcp/server.py"],
"env": {
"OMNIWEB_API_BASE": "http://127.0.0.1:5002",
"OMNIWEB_JWT_SECRET": "<clé JWT_SECRET_KEY du backend>",
"MCP_TRANSPORT": "stdio"
}
}
}
}
Pour un serveur distant HTTP streamable depuis Claude Desktop, utilisez un pont mcp-remote ou la configuration de serveur HTTP prise en charge par votre version de Desktop, pointant vers http://<host>:5005/mcp avec l'en-tête Authorization: Bearer <MCP_AUTH_TOKEN>.
Remarques de sécurité
- Le contrôle des appareils nécessite le
MCP_AUTH_TOKENconfiguré sur le transport HTTP. Sans jeton, le serveur n'autorise qu'une liaison loopback et imprime un avertissement ; une liaison non-loopback sans jeton est refusée. - Le serveur s'authentifie auprès du backend en tant qu'admin (JWT minté ou jeton fourni), donc quiconque peut atteindre
/mcpavec le jeton bearer a un contrôle total sur les appareils. TraitezMCP_AUTH_TOKENcomme un mot de passe et protégez-le avec TLS (par exemple via nginx) pour un accès hors hôte.