Servidor MCP de control de Android de OmniWeb
Un servidor MCP que envuelve el "middleware de Android" de OmniWeb (el servicio Flask omniweb-android, /api/android/*) para que un cliente MCP — Claude Code, Claude Desktop, o un cliente personalizado — pueda controlar los teléfonos Android y módems USB del laboratorio.
Es un cliente HTTP delgado sobre la API REST existente (no importa ningún interno de Flask), por lo que funciona contra cualquier instancia omniweb-android accesible.
Herramientas expuestas
| Herramienta | Firma | Qué hace |
|---|---|---|
list_devices | () | Todos los dispositivos conocidos (teléfonos + módems), en línea y fuera de línea. |
device_info | (serial) | Detalles completos de un dispositivo. |
screenshot | (serial) → imagen PNG | Pantalla actual (universal: teléfonos scrcpy Y dispositivos de captura de pantalla antiguos). |
tap | (serial, x, y) | Toca en las coordenadas de píxeles. |
swipe | (serial, x1, y1, x2, y2, ms=200) | Deslizar/arrastrar/lanzar. |
input_text | (serial, text) | Escribir en el campo enfocado. |
key | (serial, name) | Presionar atrás/inicio/recent/enter/borrar/poder/menu/subir_volumen/bajar_volumen. |
adb_shell | (serial, command, timeout=30) → {stdout, stderr, return_code} | Comando adb shell arbitrario (herramienta de poder). |
list_scripts | () | La biblioteca de scripts de prueba del dispositivo. |
run_script | (serials, file, params={}) | Ejecutar un script en varios dispositivos; devuelve identificadores de ejecución. |
get_run | (run_id) | Resultado de una ejecución de script (estado/stdout/código_de_retorno). |
at_command | (serial, command, read_ms=0, timeout_ms=0) | Comando AT en bruto a un módem USB. |
send_sms | (serial, number, text) | Enviar un SMS desde un módem. |
Configuración (variables de entorno)
Objetivo del backend:
OMNIWEB_API_BASE— URL base del servicio de Android. Por defectohttp://127.0.0.1:5002. El prefijo/api/androidse agrega automáticamente.
Autenticación del backend (elija UNO):
OMNIWEB_JWT— un token de acceso al backend preemitido (Bearer), OOMNIWEB_JWT_SECRET— laJWT_SECRET_KEYdel backend. El servidor entonces emite un JWT de administrador de corta duración y lo actualiza automáticamente.OMNIWEB_JWT_TTL(segundos, por defecto 3600) controla su duración.
La propia puerta de entrada de este servidor MCP:
MCP_TRANSPORT—http(por defecto, HTTP transmitible para clientes remotos) ostdio(localclaude mcp add).MCP_HOST/MCP_PORT— dirección de enlace para el transporte http. Por defecto127.0.0.1:5005.MCP_AUTH_TOKEN— token bearer que un cliente MCP remoto debe presentar. Requerido para enlazar a algo diferente de localhost — el servidor rechaza un enlace no de bucle sin él (fallo cerrado). En/mcpel token es verificado por middleware;/y/healthestán abiertos para chequeos de salud.
Ejecútalo
venv (autocontenido)
cd /opt/omniweb-mcp # o donde sea que hayas puesto 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 JWT_SECRET_KEY del backend>
export MCP_TRANSPORT=http
export MCP_HOST=0.0.0.0
export MCP_PORT=5005
export MCP_AUTH_TOKEN=<un token aleatorio largo>
venv/bin/python server.py
systemd (producción)
Se proporciona una unidad en packaging/omniweb-android-mcp.service. Lee
/etc/omniweb/omniweb.env (para JWT_SECRET_KEY → se vuelve a exportar como
OMNIWEB_JWT_SECRET, ver más abajo) además de /etc/omniweb/android-mcp.env para los
secretos específicos de MCP. Crea ese archivo de configuración (chmod 600):
# /etc/omniweb/android-mcp.env
OMNIWEB_JWT_SECRET=<mismo valor que JWT_SECRET_KEY en omniweb.env>
MCP_AUTH_TOKEN=<un token aleatorio largo>
Luego:
sudo cp packaging/omniweb-android-mcp.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now omniweb-android-mcp
El archivo de entorno del backend nombra el secreto JWT como
JWT_SECRET_KEY; este servidor leeOMNIWEB_JWT_SECRET. EstableceOMNIWEB_JWT_SECRETexplícitamente enandroid-mcp.env(copia el valor) para que los nombres coincidan.
Conectar desde Claude Code
Remoto (HTTP transmitible), con autenticación:
claude mcp add --transport http android-control http://<host>:5005/mcp \
--header "Authorization: Bearer <MCP_AUTH_TOKEN>"
Local (stdio), apuntando el servidor a un backend y emitiendo su propio JWT:
claude mcp add android-control \
-e OMNIWEB_API_BASE=http://127.0.0.1:5002 \
-e OMNIWEB_JWT_SECRET=<backend JWT_SECRET_KEY> \
-e MCP_TRANSPORT=stdio \
-- /opt/omniweb-mcp/venv/bin/python /opt/omniweb-mcp/server.py
Luego en Claude Code: /mcp para confirmar que se conectó, y prueba
list_devices.
Conectar desde Claude Desktop
claude_desktop_config.json — lanzamiento 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": "<backend JWT_SECRET_KEY>",
"MCP_TRANSPORT": "stdio"
}
}
}
}
Para un servidor remoto HTTP transmitible desde Claude Desktop, utiliza un puente mcp-remote
o la configuración del servidor HTTP soportada por tu versión de Desktop, apuntando a
http://<host>:5005/mcp con el encabezado Authorization: Bearer <MCP_AUTH_TOKEN>.
Notas de seguridad
- El control de dispositivos requiere el
MCP_AUTH_TOKENconfigurado en el transporte HTTP. Sin un token, el servidor solo permite un enlace de bucle y muestra una advertencia; un enlace no de bucle sin un token es rechazado. - El servidor se autentica con el backend como un administrador (JWT emitido o token proporcionado), por lo que cualquier persona que pueda acceder a
/mcpcon el token bearer tiene control total sobre los dispositivos. TrataMCP_AUTH_TOKENcomo una contraseña y protégelo con TLS (por ejemplo, a trav��s de nginx) para acceso fuera del host.