Skip to main content
Glama
README.md
# mcp-esieabot

Serveur MCP (Model Context Protocol) pour le contrôle de l'esieabot via Claude Desktop ou le MCP Inspector.  
Développé dans le cadre du TD3 — Module Python ING3, ESIEA Paris.

**Auteure :** Vanelle Stéphanie MANGOUA DJOUSSEU  
**Email :** vanellestephanie.mangouadjousseu@et.esiea.fr  
**Dépôt :** https://gitlab.esiea.fr/stephanie_mangoua/mcp-esieabot

---

## Présentation

Ce projet expose les capacités de l'esieabot (moteurs, servomoteur, caméra) sous forme de **tools MCP**, permettant à un LLM comme Claude de piloter le robot en langage naturel :

> *« Avance pendant 2 secondes, tourne à droite, puis prends une photo »*

Claude appelle automatiquement les tools MCP correspondants et retourne les résultats dans la conversation, y compris les images capturées par la caméra.

---

## Architecture choisie : Architecture B — Serveur MCP sur le PC

Le serveur MCP tourne sur le PC. Il se connecte au démon `pigpiod` du Raspberry Pi à distance via le réseau (port 8888) et à la caméra via SSH.

```
Votre PC                                         Raspberry Pi
┌────────────────────────────────┐              ┌──────────────────┐
│  Claude Desktop (client MCP)   │              │                  │
│             │                  │              │  pigpiod :8888   │
│             ▼                  │              │  (GPIO)          │
│  server.py (FastMCP)           │── pigpio ───►│  ├─ Moteurs      │
│  http://localhost:8000/mcp     │── SSH ──────►│  ├─ Servos       │
└────────────────────────────────┘              │  └─ Caméra       │
                                                └──────────────────┘
```

**Avantages de l'Architecture B :**
- Aucun problème CORS/firewall — tout MCP est en localhost
- Debug facile depuis l'IDE (breakpoints, logs en temps réel)
- Rechargement instantané sans déploiement Git sur le Pi
- Mode simulation intégré pour développer sans robot

---

## Structure du projet

```
mcp-esieabot/
├── server.py              ← Serveur MCP principal (tools, resources, prompt)
├── robot/
│   ├── __init__.py        ← Auto-détection pigpio (stub / local / remote)
│   ├── motors.py          ← Contrôle des moteurs DC via pigpiod
│   ├── servos.py          ← Contrôle du servomoteur via pigpiod
│   ├── camera.py          ← Capture photo via SSH (Architecture B)
│   └── stub.py            ← Simulation pigpio pour développement local
├── captures/              ← Photos capturées localement (créé automatiquement)
│   ├── capture1.jpg
│   ├── capture2.jpg
│   └── capture3.jpg
├── debug_photo.jpg        ← Photo retournée par take_photo en mode simulation
├── pyproject.toml
├── .gitignore
└── README.md
```

---

## Prérequis

- Python **3.11+**
- [Poetry](https://python-poetry.org/) comme gestionnaire de projet
- Accès SSH sans mot de passe vers l'esieabot
- `pigpiod` configuré en écoute réseau sur le Pi (port 8888)

### Dépendances Python

| Package | Version |
|---------|---------|
| `mcp[cli]` | >=1.26.0, <2.0.0 |
| `pigpio` | >=1.78, <2.0 |

Installation :

```bash
poetry install
```

---

## Auto-détection de l'environnement

`robot/__init__.py` détecte automatiquement le mode de fonctionnement au démarrage :

| Situation | `ESIEABOT_HOST` | `pigpio` installé ? | Mode activé |
|-----------|-----------------|---------------------|-------------|
| Développement PC pur | Non défini | Non | **Stub** — simulation console |
| Architecture B (PC → Pi) | `192.168.x.x` | Oui | **Remote** — connexion pigpio distante |
| Architecture A (sur le Pi) | Non défini | Oui | **Local** — pigpiod local |

### Mode simulation — Stub GPIO

`robot/stub.py` simule tous les appels GPIO dans la console sans aucun matériel :

```
[STUB] pigpio connecté (mode simulation — cible: local)
[STUB] GPIO 24 → OUTPUT
[STUB] GPIO 24 = HIGH
[STUB] GPIO 7 = HIGH
[STUB] Servo GPIO 16 : pulse = 1500µs
[STUB] pigpio déconnecté
```

### Mode simulation — Caméra

Si `ESIEABOT_HOST` n'est pas défini, `camera.py` retourne automatiquement `debug_photo.jpg` au lieu de tenter une connexion SSH. Cette photo (prise depuis la perspective du robot, au ras du sol) permet de tester le tool `take_photo` complètement hors ligne sans aucun crash.

---

## Configuration de l'esieabot

### 1. Activer pigpiod en écoute réseau

Par défaut, `pigpiod` n'écoute que sur localhost. Pour l'Architecture B :

```bash
ssh pi@<IP_DE_TON_ESIEABOT>
sudo systemctl edit pigpiod
```

Ajouter :

```ini
[Service]
ExecStart=
ExecStart=/usr/bin/pigpiod -n
```

```bash
sudo systemctl daemon-reload
sudo systemctl restart pigpiod

# Vérification — doit afficher une ligne avec *:8888
ss -tlnp | grep 8888
```

### 2. Configurer SSH sans mot de passe

```bash
# Sur votre PC
ssh-keygen -t ed25519        # si pas déjà fait
ssh-copy-id pi@<IP_DE_TON_ESIEABOT>

# Test
ssh pi@<IP_DE_TON_ESIEABOT> "echo OK"
```

---

## Lancement du serveur

### Mode simulation — sans robot

```bash
poetry run python server.py
```

Sortie attendue :

```
⚠️ Aucun hôte caméra. Passage en mode SIMULATION (Photo locale).
⚠️ pigpio non trouvé. Passage en mode SIMULATION (Stub global).
INFO:     Uvicorn running on http://0.0.0.0:8000
```

### Mode réel — Architecture B (PC → Pi)

```bash
# Linux / macOS
ESIEABOT_HOST=<IP_DE_TON_ESIEABOT> poetry run python server.py

# Windows (PowerShell)
$env:ESIEABOT_HOST="<IP_DE_TON_ESIEABOT>"; poetry run python server.py

# Windows (cmd)
set ESIEABOT_HOST=<IP_DE_TON_ESIEABOT> && poetry run python server.py
```

Sortie attendue :

```
✅ Caméra configurée pour l'hôte : <IP>
🤖 Robot connecté physiquement (pigpio → <IP>)
INFO:     Uvicorn running on http://0.0.0.0:8000
```

Le serveur écoute sur **http://localhost:8000/mcp**.

---

## Primitives MCP exposées

### Tools (12)

| Tool | Description | Validation entrée |
|------|-------------|-------------------|
| `ping` | Vérifie que le serveur est en ligne | — |
| `identify` | Hostname, OS, version Python du robot | — |
| `move_forward` | Avance en ligne droite avec suivi de progression temps réel | durée [0.1–10.0 s] |
| `move_backward` | Recule en ligne droite | durée [0.1–10.0 s] |
| `turn_left` | Pivote à gauche sur place | durée [0.1–5.0 s] |
| `turn_right` | Pivote à droite sur place | durée [0.1–5.0 s] |
| `emergency_stop` | Arrêt immédiat de tous les moteurs | — |
| `set_servo_angle` | Positionne le servomoteur à un angle précis | angle [0–180°] |
| `detach_servo` | Désarme le servomoteur (coupe le signal PWM) | — |
| `take_photo` | Prend une photo et la retourne directement à Claude | — |
| `list_captures` | Liste toutes les photos dans `./captures/` avec leur taille | — |
| `get_capture` | Affiche une photo spécifique par nom de fichier | nom de fichier |

### Resources (2)

| URI | Description | Mode simulation |
|-----|-------------|-----------------|
| `robot://status` | Température CPU, mémoire, uptime du Pi via SSH | Retourne `(Mode simulation — Hors ligne)` |
| `robot://captures` | Liste statique des captures disponibles | Liste les fichiers présents dans `./captures/` |

### Prompt (1)

| Prompt | Paramètres | Description |
|--------|------------|-------------|
| `patrol_mission` | `area` (défaut: `"bureau"`), `photo_count` (défaut: `3`) | Génère une mission de patrouille complète pour Claude |

Exemple d'utilisation dans Claude Desktop :
> *« Utilise le prompt patrol_mission pour le couloir avec 2 photos »*

---

## GPIO de l'esieabot

| Composant | GPIO BCM | Fonction |
|-----------|----------|----------|
| Moteur gauche — avance | 24 | Sens marche avant gauche |
| Moteur gauche — recul | 23 | Sens marche arrière gauche |
| Moteur droit — avance | 7 | Sens marche avant droit |
| Moteur droit — recul | 8 | Sens marche arrière droit |
| Servomoteur | 16 | Angle PWM (500–2500 µs) |

---

## Connexion avec Claude Desktop

Éditez le fichier de configuration de Claude Desktop :

- **Windows :** `%APPDATA%\Claude\claude_desktop_config.json`
- **macOS :** `~/Library/Application Support/Claude/claude_desktop_config.json`

```json
{
  "mcpServers": {
    "esieabot": {
      "type": "streamable-http",
      "url": "http://localhost:8000/mcp"
    }
  }
}
```

Redémarrez Claude Desktop. Les 12 tools `esieabot` apparaissent automatiquement.

### Exemples d'interactions avec Claude

```
« Quel est l'état de mon robot ? »
→ Claude consulte la resource robot://status

« Avance pendant 2 secondes puis tourne à droite »
→ Claude appelle move_forward(duration=2.0) puis turn_right(duration=0.5)

« Prends une photo »
→ Claude appelle take_photo() et affiche l'image dans la conversation

« Liste les captures disponibles »
→ Claude appelle list_captures() ou consulte robot://captures

« Utilise le prompt de patrouille pour le bureau avec 2 photos »
→ Claude charge patrol_mission(area="bureau", photo_count=2) et exécute la mission
```

---

## Test avec le MCP Inspector

```bash
npx -y @modelcontextprotocol/inspector
```

Connectez-vous à `http://localhost:8000/mcp` pour tester chaque tool individuellement sans Claude Desktop.

---

## Bonus implémentés

| Bonus | Description | Implémentation |
|-------|-------------|----------------|
| **C** — Resource captures | `robot://captures` liste les photos disponibles passivement | `@mcp.resource("robot://captures")` dans `server.py` |
| **D** — Progress reporting | `move_forward` reporte la progression en temps réel par paliers | `ctx.report_progress()` + `asyncio.sleep()` par paliers de 1/5 |
| **E** — Connexion pigpio partagée | Une seule instance `pigpio.pi()` partagée entre moteurs et servos | Instance unique créée dans `robot_lifespan()`, injectée via `MotorController(pi=pi)` et `ServoController(pi=pi)` |

---

## Auteure

**Vanelle Stéphanie MANGOUA DJOUSSEU**  
Étudiante ING3 — Systèmes Embarqués et Autonomes  
ESIEA Paris (Ivry-sur-Seine)  
vanellestephanie.mangouadjousseu@et.esiea.fr