dijkstra-mcp-server
by BNJ02
README.md
# Serveur MCP Dijkstra
Serveur MCP minimal (un fichier) exposant l'algorithme de Dijkstra à un agent LLM.
Support de cours : le point intéressant n'est pas l'algo mais **comment l'agent transmet le graphe**.
## Format du graphe
Une arête par ligne, trois champs séparés par des espaces :
```
<noeud_a> <noeud_b> <cout>
```
- graphe **non orienté** : `Paris Dijon 315` crée `Paris->Dijon` **et** `Dijon->Paris`
- coûts **positifs ou nuls** (contrainte de Dijkstra)
- lignes vides et lignes commençant par `#` ignorées
Pourquoi ce format plutôt que du JSON : un LLM l'écrit sans erreur de syntaxe (rien à
équilibrer), il se lit tel quel au tableau, et il se parse en quelques lignes.
Le graphe voyage **dans l'appel d'outil** — le serveur ne stocke rien.
## Outils
| Outil | Arguments | Retour |
|---|---|---|
| `shortest_path` | `graph`, `start`, `end` | chemin optimal, coût total, détail des tronçons |
| `all_distances` | `graph`, `start` | coût minimal **et chemin** vers **tous** les nœuds, trié |
`all_distances` montre que Dijkstra construit l'arbre complet des plus courts chemins,
pas seulement une paire départ/arrivée. Il renvoie aussi les chemins : sans ça, un agent
à qui on demande un tableau récapitulatif rappelle `shortest_path` une fois par
destination. Leçon de design MCP : **un outil qui ne rend qu'une partie de la réponse
attendue se fait contourner.**
## Exemple
Graphe (coûts de trajet) :
```
Paris Lyon 550
Paris Dijon 315
Dijon Lyon 195
Lyon Marseille 315
Dijon Geneve 200
Geneve Marseille 420
```
`shortest_path(graph, "Paris", "Marseille")` :
```
Chemin le moins coûteux : Paris -> Dijon -> Lyon -> Marseille
Coût total : 825
Détail des tronçons :
Paris -> Dijon : 315
Dijon -> Lyon : 195
Lyon -> Marseille : 315
```
Le détour par Dijon (825) bat la route directe Paris–Lyon–Marseille (550+315 = 865)
et la route par Genève (315+200+420 = 935) : l'arête directe évidente n'est pas la bonne.
## Prompts de démonstration
À coller tels quels dans une session Claude Code une fois le serveur enregistré.
**Prompt 1 — une paire départ/arrivée** (déclenche `shortest_path`, un seul appel) :
```
Avec le serveur MCP dijkstra, trouve-moi le trajet le moins cher de Paris à Marseille.
Paris Lyon 550
Paris Dijon 315
Dijon Lyon 195
Lyon Marseille 315
Dijon Geneve 200
Geneve Marseille 420
```
Attendu : `Paris -> Dijon -> Lyon -> Marseille`, coût **825**.
**Prompt 2 — toutes les destinations** (déclenche `all_distances`, un seul appel) :
```
Avec dijkstra, donne-moi le coût minimal depuis Paris vers toutes les autres villes.
Paris Lyon 550
Paris Dijon 315
Dijon Lyon 195
Lyon Marseille 315
Dijon Geneve 200
Geneve Marseille 420
```
Attendu : un tableau des 5 villes avec coût **et** chemin.
> Observé en cours : tant que `all_distances` ne renvoyait que les coûts, l'agent
> l'ignorait et appelait `shortest_path` **4 fois** pour reconstituer les chemins.
> C'est exactement le piège décrit plus haut — un outil qui ne rend qu'une partie de
> la réponse attendue se fait contourner. Bon moment pour faire la démo des deux
> versions côte à côte.
**Prompt 3 — sans graphe fourni** (l'agent doit produire lui-même le bon format) :
```
Utilise le serveur dijkstra pour trouver le chemin le moins coûteux
de A à F dans un petit graphe de 6 nœuds de ton choix.
```
## Carte
`carte.py` produit deux figures dans `images/` à partir du **même** graphe que le serveur
(constante `GRAPHE_EXEMPLE` dans `server.py`) :
| Fichier | Usage |
|---|---|
| `images/carte_graphe.png` / `.svg` | l'énoncé : 5 villes, 6 arêtes, les coûts |
| `images/carte_solution.png` / `.svg` | la correction : `Paris → Dijon → Lyon → Marseille` en rouge |
Le chemin surligné est **calculé par l'algorithme**, jamais codé en dur : changer un coût
dans `GRAPHE_EXEMPLE` et relancer suffit à mettre la carte à jour.
Les contours de la France et de la Suisse sont téléchargés une fois puis mis en cache dans
`data/` (2 ko au total) — le script tourne offline ensuite.
```bash
.venv/bin/python carte.py
```
## Installation / enregistrement
Deux environnements, deux besoins :
- **le serveur** tourne avec le venv MCP partagé `/home/bnj/mcp_servers/.venv`
(dépendance unique : `fastmcp>=3.4.2`, déjà présent) ;
- **la carte** tourne avec le `.venv` local du projet, qui ajoute matplotlib sans polluer
le venv partagé :
```bash
uv venv .venv
uv pip install --python .venv/bin/python -r requirements-carte.txt
```
Enregistrement du serveur dans Claude Code :
```bash
claude mcp add dijkstra -- /home/bnj/mcp_servers/.venv/bin/python /home/bnj/Documents/djikstra_mcp_server/server.py
```
## Tests
```bash
/home/bnj/mcp_servers/.venv/bin/python test_server.py
```
Couvre : parsing, optimalité du chemin, les deux outils, les erreurs (nœud inconnu,
coût négatif, ligne malformée, graphe déconnecté) et un appel bout-en-bout via un
client MCP en mémoire.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues