mcp-appium
# mcp-appium
[](https://pypi.org/project/mcp-appium/)
[](https://pypi.org/project/mcp-appium/)
[](https://github.com/julien-becheny/mcp-appium/actions/workflows/qualite.yml)
[](LICENSE)
Un assistant qui écrit des tests mobiles invente des sélecteurs. Il propose
`accessibility_id=bouton_valider` parce que c'est ce qu'un développeur aurait
écrit, et le test échoue parce que l'application expose autre chose.
Ce serveur MCP lui donne **l'écran réel**.
```
pip install mcp-appium
```
[Le paquet sur PyPI](https://pypi.org/project/mcp-appium/)
## Ce qu'il fait
Onze outils, exposés à l'assistant via le Model Context Protocol :
| Outil | Rôle |
|---|---|
| `connect_to_session` | Se rattache à une session Appium **déjà ouverte** |
| `get_page_source` | L'arbre de l'écran, simplifié ou brut |
| `find_elements` | Recherche par sélecteur ou par texte |
| `suggest_locators` | Des sélecteurs qui existent, classés par robustesse |
| `get_element_info` | Attributs, position, état d'un élément |
| `screenshot` | L'écran, réduit avant envoi |
| `tap_element` | Clic, avec vérification que l'écran a bougé |
| `type_text` | Saisie dans un champ |
| `go_back` | Retour arrière |
| `get_session_info` | Plateforme, appareil, identifiant de session |
| `close_session` | Libère l'appareil, **si ce serveur a ouvert la session** |
Android, iOS, iPadOS et Windows.
## Le cas courant : observer une session existante
Un test tourne, il échoue sur un élément. Tu demandes à l'assistant ce que
l'écran contient vraiment.
```
connect_to_session()
```
Sans argument, le serveur cherche une session active sur
`http://127.0.0.1:4723` et s'y rattache. **Il ne crée rien, ne redémarre rien**,
et aucune configuration n'est nécessaire.
C'est le mode à privilégier : l'assistant voit exactement ce que le test voit,
au moment où il le voit.
## Créer une session
Si aucune session n'existe, le serveur peut en ouvrir une. Il lui faut alors des
capabilities, déclarées dans `appium-caps.json` à la racine de ton projet :
```json
{
"platformName": "Android",
"automationName": "UiAutomator2",
"appPackage": "com.exemple.app",
"appActivity": ".MainActivity"
}
```
Les clés sont préfixées par `appium:` automatiquement quand il le faut.
Plusieurs plateformes dans le même fichier :
```json
{
"android": { "platformName": "Android", "automationName": "UiAutomator2", "appPackage": "com.exemple.app" },
"ios": { "platformName": "iOS", "automationName": "XCUITest", "bundleId": "com.exemple.app" }
}
```
La variable `MCP_APPIUM_PLATFORM` choisit laquelle. À défaut, la première
déclarée. Deux autres variables existent : `MCP_APPIUM_CAPS` pour passer le JSON
directement, et `MCP_APPIUM_CAPS_FILE` pour désigner un autre fichier.
## Déclarer le serveur
Dans VS Code, `.vscode/mcp.json` :
```json
{
"servers": {
"appium": {
"type": "stdio",
"command": "mcp-appium"
}
}
}
```
Le format est le même pour les autres clients MCP : une commande, transport
standard.
## Le parti pris qui compte : borner les sorties
Un arbre de vue Appium brut dépasse couramment les cinquante mille caractères.
Envoyé tel quel, il sature la fenêtre de contexte du modèle avant de lui avoir
appris quoi que ce soit. Pire : ce qui entre dans le contexte y reste, et se
repaie à chaque échange suivant de la conversation.
Toutes les sorties sont donc plafonnées, et le serveur le dit quand il coupe :
- arbre simplifié à 400 lignes, avec les seuls attributs qui servent à cibler ;
- source brute à 40 000 caractères ;
- 15 éléments détaillés au maximum dans une recherche ;
- captures réduites à 1280 pixels de large.
Un outil d'inspection qui ne borne pas ses sorties est inutilisable en
conversation, quelle que soit la qualité de ce qu'il expose.
## Deux autres partis pris
**Un tap vérifie son effet.** `tap_element` compare l'écran avant et après, et
signale explicitement un clic resté sans conséquence. Un élément désactivé ou
recouvert répond à `click()` sans rien faire : sans cette vérification,
l'assistant croit avoir avancé et enchaîne dans le vide.
**Une session ne se ferme que si on l'a ouverte.** `close_session` libère
l'appareil quand le serveur a créé la session, et se contente de s'en détacher
sinon. Fermer la session d'un test en cours couperait ce test.
**`suggest_locators` classe par robustesse.** L'identifiant d'accessibilité
d'abord, le XPath sur le texte en dernier, avec la mention qu'il cassera au
prochain changement de libellé.
## Ce qu'il ne fait pas
Il **n'écrit pas de tests** et n'impose aucun framework. Il expose l'état de
l'application, l'assistant fait le reste avec les outils que tu utilises déjà.
Il ne dépend d'**aucun service d'IA**. Ni clé d'API, ni compte, ni appel sortant :
le seul réseau qu'il touche est ton serveur Appium local.
Il ne **remplace pas Appium Inspector** pour l'exploration manuelle. Il sert à
donner ces informations à un modèle, ce qu'une interface graphique ne sait pas
faire.
## Compatibilité
| | |
|---|---|
| Python | 3.10 et plus |
| SDK MCP | **2.0 et plus** |
| Appium | 2 et 3 |
| Plateformes | Android, iOS, iPadOS, Windows |
Le SDK MCP 2 a renommé `FastMCP` en `MCPServer` : le code écrit pour la version 1
ne fonctionne pas avec celle-ci, et inversement. La contrainte est donc
volontairement stricte.
## Licence
MIT.
TDQS
Scored across 11 tools
Most tools are clearly distinct: session management, element lookup, and actions. Minor overlap exists between get_page_source/screenshot and find_elements/get_element_info, but descriptions make the differences clear.
All tool names follow a consistent snake_case verb_noun pattern (connect_to_session, get_page_source, type_text, find_elements, etc.). go_back is a phrasal verb but matches the style.
11 tools is well-scoped for an Appium MCP server. Each tool serves a clear purpose in session management, element inspection, or interaction, with no redundant or unnecessary entries.
Core workflows like connecting, inspecting, tapping, typing, and navigating back are covered. However, common mobile interactions such as swipe, scroll, long press, and wait-for-element are missing, which could block typical automation flows.