Aller au contenu principal

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

OutilSignatureCe 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éfaut http://127.0.0.1:5002. Le préfixe /api/android est ajouté automatiquement.

Authentification du backend (choisissez UN) :

  • OMNIWEB_JWT — un jeton d'accès backend pré-minté (Bearer), OU
  • OMNIWEB_JWT_SECRET — la JWT_SECRET_KEY du 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_TRANSPORThttp (par défaut, HTTP streamable pour les clients distants) ou stdio (local claude mcp add).
  • MCP_HOST / MCP_PORT — adresse de liaison pour le transport http. Par défaut 127.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 /health sont 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 lit OMNIWEB_JWT_SECRET. Définissez OMNIWEB_JWT_SECRET explicitement dans android-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 &lt;MCP_AUTH_TOKEN>.

Remarques de sécurité

  • Le contrôle des appareils nécessite le MCP_AUTH_TOKEN configuré 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 /mcp avec le jeton bearer a un contrôle total sur les appareils. Traitez MCP_AUTH_TOKEN comme un mot de passe et protégez-le avec TLS (par exemple via nginx) pour un accès hors hôte.