192 lines
6.9 KiB
Markdown
192 lines
6.9 KiB
Markdown
# 🧩 Guide MCP (Model Context Protocol)
|
|
|
|
ObsiGate expose ses vaults à des **clients MCP externes** (Claude Desktop, Cursor,
|
|
Cline, tout client compatible MCP) via un serveur **Streamable HTTP** monté sur
|
|
`/mcp`. Les outils sont les **mêmes** que ceux de l'assistant in-app : la couche
|
|
`backend/tools/` est la source unique de vérité.
|
|
|
|
> **Statut :** livré (#79 phase E + F) · **Dernière mise à jour :** 2026-09
|
|
> **Voir aussi :** [`features/ai-tools-mcp.md`](../features/ai-tools-mcp.md) ·
|
|
> [`AI_ARCHITECTURE_GUIDE.md`](../AI_ARCHITECTURE_GUIDE.md) ·
|
|
> [API REST](./API_REST.md) · [Assistant IA & Forge](./ASSISTANT_IA_FORGE.md)
|
|
|
|
---
|
|
|
|
## 1. Prérequis
|
|
|
|
1. Une instance ObsiGate accessible (locale ou distante).
|
|
2. Une **clé API** (recommandé) ou un **jeton JWT** valide
|
|
(`Authorization: Bearer <token>`). Une seule clé fonctionne pour l'API REST
|
|
**et** le MCP. Créez-la depuis l'interface (Configurations → 🔑 Clés API & MCP)
|
|
ou via `POST /api/auth/tokens` — voir [API REST §2.2](./API_REST.md#22-clés-api-longue-durée-recommandé-pour-scripts--mcp).
|
|
3. Si l'authentification est désactivée (`OBSIGATE_AUTH_ENABLED=false`), le
|
|
serveur MCP accepte un utilisateur anonyme disposant de tous les vaults.
|
|
|
|
> Le transport `stdio` n'est pas encore supporté ; utilisez le transport HTTP
|
|
> (un pont local type `mcp-remote` si votre client ne gère pas nativement le
|
|
> Streamable HTTP distant).
|
|
|
|
---
|
|
|
|
## 2. Endpoint & protocole
|
|
|
|
| Élément | Valeur |
|
|
|---|---|
|
|
| URL | `https://<obsigate>/mcp` |
|
|
| Transport | Streamable HTTP (`POST` JSON-RPC 2.0, `Accept: application/json, text/event-stream`) |
|
|
| Auth | `Authorization: Bearer <JWT>` |
|
|
| Protocole MCP | `2025-03-26` (négocié à l'`initialize`) |
|
|
| Réponses | JSON (`json_response=True`) |
|
|
|
|
Handshake minimal :
|
|
|
|
```bash
|
|
curl -sS https://obsigate.example/mcp \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-H "Accept: application/json, text/event-stream" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
|
|
"protocolVersion":"2025-03-26","capabilities":{},
|
|
"clientInfo":{"name":"curl","version":"1.0"}}}'
|
|
```
|
|
|
|
La réponse contient l'en-tête `Mcp-Session-Id` à réutiliser pour les appels
|
|
suivants (`tools/list`, `tools/call`, `resources/read`, …).
|
|
|
|
---
|
|
|
|
## 3. Configuration des clients
|
|
|
|
### Claude Desktop (via pont `mcp-remote`)
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"obsigate": {
|
|
"command": "npx",
|
|
"args": [
|
|
"-y", "mcp-remote",
|
|
"https://obsigate.example/mcp",
|
|
"--header", "Authorization: Bearer ${OBSIGATE_TOKEN}"
|
|
],
|
|
"env": { "OBSIGATE_TOKEN": "eyJ..." }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Cursor
|
|
|
|
`.cursor/mcp.json` :
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"obsigate": {
|
|
"url": "https://obsigate.example/mcp",
|
|
"headers": { "Authorization": "Bearer eyJ..." }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Client générique (config raccourcie)
|
|
|
|
```json
|
|
{"mcpServers": {"obsigate": {
|
|
"url": "http://localhost:2020/mcp",
|
|
"headers": {"Authorization": "Bearer <clé API>"}
|
|
}}}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Primitives exposées
|
|
|
|
### 4.1 Tools
|
|
|
|
Les outils de **lecture/recherche** sont exposés directement. Les outils
|
|
**d'écriture/destructifs** sont exposés via une paire **two-step** :
|
|
`propose_<tool>` (aperçu + jeton de confirmation, aucune modification) puis
|
|
`apply_<tool>` (consomme le jeton et exécute).
|
|
|
|
| Catégorie | Outils |
|
|
|---|---|
|
|
| Vaults / navigation | `list_vaults`, `list_directory`, `list_all_files` |
|
|
| Lecture | `read_file`, `read_file_raw`, `get_backlinks`, `list_backups`, `diff_backup`, `get_graph` |
|
|
| Recherche | `search_fulltext`, `search_advanced`, `search_paths`, `list_tags`, `suggest_tags`, `list_recent` |
|
|
| Écriture (propose/apply) | `create_file`, `create_directory`, `edit_file`, `append_to_file`, `restore_backup` |
|
|
| Destructif (propose/apply) | `rename_file`, `rename_directory`, `move_path`, `replace_in_files`, `delete_file`, `delete_directory` |
|
|
|
|
Flux d'une mutation :
|
|
|
|
```text
|
|
1. tools/call { name: "propose_edit_file",
|
|
arguments: { vault, path, content } }
|
|
→ { tool, arguments, diff, confirmation_token, expires_in }
|
|
|
|
2. (l'utilisateur / l'agent valide)
|
|
|
|
3. tools/call { name: "apply_edit_file",
|
|
arguments: { confirmation_token } }
|
|
→ { ok: true, data: { ... } }
|
|
```
|
|
|
|
Le jeton est **signé (JWT), à usage unique et à durée de vie limitée**
|
|
(`OBSIGATE_MCP_CONFIRMATION_TTL`, défaut 300 s). Un rejeu renvoie `token_reused`.
|
|
|
|
### 4.2 Resources
|
|
|
|
| URI | Contenu |
|
|
|---|---|
|
|
| `vault://<name>` | Vault accessible (métadonnées, nombre de fichiers) |
|
|
| `vault://<name>/<path>` | Contenu d'un fichier (lecture seule, **secrets redactés**) |
|
|
|
|
### 4.3 Prompts
|
|
|
|
`summarize-directory`, `generate-note`, `find-related`.
|
|
|
|
---
|
|
|
|
## 5. Sécurité
|
|
|
|
- **Permissions par vault** : `check_vault_access` est appliqué à chaque outil
|
|
et chaque resource ; un utilisateur ne voit que ses vaults.
|
|
- **Anti path-traversal** : `resolve_safe_path` rejette tout chemin hors du vault.
|
|
- **Confirmation two-step** pour toute mutation (jeton signé, usage unique).
|
|
- **Toggle par vault** `aiDestructiveTools` (défaut : activé) : le désactiver
|
|
bloque rename/move/replace/delete tout en laissant create/edit/append.
|
|
- **Backup automatique** avant chaque opération destructive.
|
|
- **Rate limiting** : par jeton et par outil
|
|
(`OBSIGATE_TOOL_RATE_LIMIT`, `OBSIGATE_TOOL_RATE_LIMIT_PER_TOOL`,
|
|
`OBSIGATE_TOOL_RATE_WINDOW`). Une limite dépassée renvoie le code `rate_limited`.
|
|
- **Redaction des secrets** : les résultats d'outils (lectures, diffs, extraits
|
|
de recherche) sont nettoyés avant tout retour au client.
|
|
- **Audit** : chaque appel est journalisé (`data/audit.log`, action
|
|
`ai_tool_call`) avec arguments sensibles résumés.
|
|
|
|
### Variables d'environnement
|
|
|
|
| Variable | Défaut | Rôle |
|
|
|---|---|---|
|
|
| `OBSIGATE_MCP_CONFIRMATION_TTL` | `300` | Durée de vie (s) des jetons de confirmation |
|
|
| `OBSIGATE_TOOL_RATE_LIMIT` | `60` | Appels d'outils max par identité et par fenêtre |
|
|
| `OBSIGATE_TOOL_RATE_LIMIT_PER_TOOL` | = global | Appels max par outil et par fenêtre |
|
|
| `OBSIGATE_TOOL_RATE_WINDOW` | `60` | Longueur de la fenêtre (s) |
|
|
| `BOOKSLM_MAX_TOOL_CALLS` | `25` | Quota d'appels d'outils par run d'agent |
|
|
| `BOOKSLM_MAX_TOOL_READ_BYTES` | `200000` | Taille max renvoyée par `read_file` |
|
|
|
|
---
|
|
|
|
## 6. Dépannage
|
|
|
|
| Symptôme | Cause probable / remède |
|
|
|---|---|
|
|
| `401 Authentification requise` | En-tête `Authorization: Bearer` absent ou jeton expiré |
|
|
| `vault_access_denied` | Le jeton n'a pas accès à ce vault (`vaults` / `_token_vaults`) |
|
|
| `destructive_tools_disabled` | `aiDestructiveTools=false` pour ce vault |
|
|
| `confirmation_required` | Appeler d'abord `propose_<tool>` puis `apply_<tool>` |
|
|
| `token_reused` / `invalid_confirmation` | Jeton déjà consommé ou expiré → refaire un `propose_` |
|
|
| `rate_limited` | Quota dépassé ; respecter `retry_after` |
|
|
| Le client ne se connecte pas | Vérifier le transport Streamable HTTP / le pont `mcp-remote` |
|