Skip to main content
Glama
Bamba4700

mcp-asterisk-socle

by Bamba4700
README.md
# Module 1 — Socle Framework MCP & Sécurité

Serveur MCP sécurisé pour la supervision d'un PBX Asterisk.

**Responsables :** Khadim GUEYE, Gnilane NIANE
**Projet :** Supervision Asterisk via Model Context Protocol

Ce module fournit le socle sur lequel se branchent :
- **Module 2** — Outils de supervision Asterisk (ARI/AMI)
- **Module 3** — Pipeline vocal Speech-to-Speech

---

## Démarrage rapide

```bash
git clone https://github.com/Bamba4700/mcp-asterisk-socle.git
cd mcp-asterisk-socle
docker compose up -d
```

Trois conteneurs démarrent :

| Service | Port | Rôle |
|---|---|---|
| `keycloak-db` | interne | Base PostgreSQL de Keycloak |
| `keycloak` | 8080 | Serveur d'identité (realm importé automatiquement) |
| `mcp-server` | 8000 | Le serveur MCP |

Console Keycloak : http://localhost:8080 (`admin` / `admin`)
Endpoint MCP : http://localhost:8000/mcp

---

## Comptes de test

| Utilisateur | Mot de passe | Rôle |
|---|---|---|
| `admin_demo` | `admin` | `admin` — accès complet |
| `superviseur_demo` | `admin` | `superviseur` — lecture, analyse, écoute |
| `operateur_demo` | `admin` | `operateur` — lecture seule |

---

## Obtenir un jeton JWT

```bash
source load_secret.sh    # récupère le client_secret depuis Keycloak

curl -s -X POST http://localhost:8080/realms/mcp-asterisk/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password" \
  -d "client_id=mcp-server" \
  -d "client_secret=$KC_CLIENT_SECRET" \
  -d "username=admin_demo" \
  -d "password=admin"
```

Le jeton est valable **5 minutes**.

---

## Ajouter un outil (Modules 2 et 3)

Créez votre fichier dans `src/tools/`, puis importez-le dans `src/server.py`.

### Outil de lecture (RBAC seul)

```python
from fastmcp.server.dependencies import CurrentAccessToken
from src.server import mcp
from src.security.rbac import require_role
from src.hitl.sanitizer import sanitize

@mcp.tool()
def list_active_channels(token=CurrentAccessToken()) -> dict:
    """Liste les canaux actifs du PBX."""
    require_role(token, "operateur")
    resultat = ...           # votre code ARI/AMI
    return sanitize(resultat)
```

### Outil de pilotage (RBAC + confirmation humaine)

```python
from fastmcp import Context
from src.hitl.confirmation import demander_confirmation

@mcp.tool()
async def hangup_channel(
    channel_id: str,
    ctx: Context,
    token=CurrentAccessToken(),
) -> str:
    """Raccroche un canal Asterisk."""
    require_role(token, "admin")
    await demander_confirmation(
        ctx, f"Confirmez le raccrochage du canal {channel_id} ?"
    )
    ...                      # votre code ARI/AMI
    return sanitize(f"Canal {channel_id} raccroche.")
```

### Règles à respecter

1. **Tout outil** appelle `require_role(token, "...")` en première ligne
2. **Tout outil de pilotage** appelle `demander_confirmation(...)` avant d'agir
3. **Toute sortie** passe par `sanitize(...)` avant d'être retournée

---

## Sécurité implémentée

| Exigence (cahier des charges A.6) | Implémentation |
|---|---|
| RBAC 3 rôles | `src/security/rbac.py` |
| Jetons JWT via Keycloak (OIDC) | `src/security/auth.py` — `JWTVerifier` |
| Interdiction du token passthrough | Le jeton n'authentifie que la session MCP |
| Consentement humain obligatoire | `src/hitl/confirmation.py` — primitive Elicitation |
| Sorties = entrées non fiables | `src/hitl/sanitizer.py` |

---

## Avertissement

Cette configuration est destinée au **développement local**.
Avant tout déploiement réel : changer les mots de passe (`admin`/`admin`,
`POSTGRES_PASSWORD`), activer HTTPS, et remplacer `start-dev` par `start`.