docs: guide complet serveur MCP pour agents externes
This commit is contained in:
@@ -0,0 +1,449 @@
|
||||
# FlowDeck — Serveur MCP : Guide complet d'intégration agents externes
|
||||
|
||||
> **Version :** 1.0 · **Date :** 2026-09-08 · **Cible :** FlowDeck v5.x
|
||||
> **Sujet :** Exposer FlowDeck comme **serveur MCP** (Model Context Protocol) pour que des agents externes
|
||||
> (Claude Desktop/Code, Cursor, OpenClaw/Hermes, n'importe quel client MCP) puissent lire et
|
||||
> modifier le workspace.
|
||||
> **Prérequis :** FlowDeck v5.x · FastAPI · SQLite WAL · agent interne déjà en place (`AgentEngine` + `ToolRegistry`)
|
||||
|
||||
---
|
||||
|
||||
## Table des matières
|
||||
|
||||
1. [Verdict : est-ce une bonne idée ?](#1-verdict)
|
||||
2. [Ce que FlowDeck a déjà (l'essentiel est fait)](#2-ce-que-flowdeck-a-déjà)
|
||||
3. [Positionnement : deux rôles complémentaires](#3-positionnement)
|
||||
4. [Architecture cible](#4-architecture-cible)
|
||||
5. [Services offerts par le serveur MCP](#5-services-offerts)
|
||||
6. [Plan d'implémentation pas à pas](#6-plan-dimplémentation)
|
||||
7. [Transport & configuration](#7-transport--configuration)
|
||||
8. [Sécurité](#8-sécurité)
|
||||
9. [Configuration des clients](#9-configuration-des-clients)
|
||||
10. [Tests & vérification](#10-tests--vérification)
|
||||
11. [Version & roadmap](#11-version--roadmap)
|
||||
12. [Liens & références](#12-liens--références)
|
||||
|
||||
---
|
||||
|
||||
## 1. Verdict {#1-verdict}
|
||||
|
||||
**Oui, c'est une excellente idée — et c'est même l'évolution naturelle du projet.** Trois raisons factuelles :
|
||||
|
||||
1. **C'est exactement ce que fait Notion.** Le guide `docs/Guide_Complet_Notion_AI.md` (déjà dans le repo)
|
||||
documente les endpoints officiels `https://mcp.notion.com/mcp` (Streamable HTTP) et `https://mcp.notion.com/sse`.
|
||||
FlowDeck est un clone de Notion : l'équivalent « API publique + agents externes » de Notion, c'est un serveur MCP.
|
||||
On ne copie pas une idée exotique, on complète la parité avec le modèle de référence.
|
||||
|
||||
2. **80 % de l'infrastructure existe déjà.** Le `ToolRegistry` (`app/services/tool_registry.py`) est déjà un
|
||||
**catalogue d'outils compatible MCP** : 22 outils, chacun avec `name` + `description` + `parameters`
|
||||
(JSON Schema) + `execute(args, user_id=...)`. C'est *exactement* le contrat qu'un serveur MCP expose.
|
||||
Le `PermissionManager` fait déjà l'autorisation, le journal `agent_actions` fait déjà l'audit + rollback,
|
||||
`public_api.py` fait déjà l'auth par token Bearer. **Il manque seulement la couche de protocole MCP.**
|
||||
|
||||
3. **Le coût marginal est minuscule.** Une dépendance (`mcp` SDK officiel), un module (`app/mcp_server.py`,
|
||||
~150 lignes), un point d'entrée. **Aucune modification du cœur de l'app** : les outils existants sont
|
||||
réutilisés tels quels, avec leurs permissions et leur audit. Le serveur MCP est un *second visage*
|
||||
de l'API existante, pas une nouvelle fonctionnalité monolithique.
|
||||
|
||||
**Ce que ça apporte concrètement :** n'importe quel agent externe (Claude Desktop, Cursor, OpenClaw/Hermes…)
|
||||
peut « voir » et piloter FlowDeck : « crée un CR de réunion dans le workspace X », « ajoute les issues du
|
||||
sprint au kanban », « résume les tâches en cours », « crée une collection avec statut/sprint », etc.
|
||||
Sans MCP, chaque agent externe devrait coder son propre client HTTP contre l'API — MCP standardise tout ça
|
||||
(un seul schéma d'outils, découverte automatique, types JSON Schema).
|
||||
|
||||
---
|
||||
|
||||
## 2. Ce que FlowDeck a déjà {#2-ce-que-flowdeck-a-déjà}
|
||||
|
||||
### 2.1 ToolRegistry — 22 outils (cœur réutilisable)
|
||||
|
||||
Fichier : `app/services/tool_registry.py`. Chaque outil est une classe `Tool` avec :
|
||||
|
||||
```python
|
||||
class Tool:
|
||||
name: str = ""
|
||||
description: str = "" # explication lisible par un LLM
|
||||
parameters: dict # JSON Schema (très exactement le format MCP)
|
||||
async def execute(self, args: dict, *, user_id: int | None = None) -> ToolResult
|
||||
```
|
||||
|
||||
`ToolRegistry.schema(scope)` retourne déjà la liste `{name, description, parameters}` — le format exact
|
||||
que `tools/list` MCP doit renvoyer. `ToolRegistry.execute(tool, args, user_id=...)` exécute avec
|
||||
vérification d'existence.
|
||||
|
||||
### 2.2 PermissionManager — autorisation
|
||||
|
||||
Fichier : `app/services/permission_manager.py`. API :
|
||||
- `can_read(workspace_id)`, `can_write(workspace_id)`, `can_destructive(workspace_id)`
|
||||
- `assert_can(tool, args, workspace_id, approval_mode)` — lève une exception si refus ;
|
||||
les outils destructifs (`delete_*`) exigent le rôle owner/admin **ou** `approval_mode == "confirm"`.
|
||||
|
||||
### 2.3 Journal d'audit + rollback
|
||||
|
||||
`AgentEngine._log_action(...)` (`app/services/agent_engine.py`) écrit chaque action dans `agent_actions`
|
||||
(payload, résultat, snapshot undo, `executed_by`). `undo_action(action_id)` restaure.
|
||||
**Le serveur MCP doit journaliser ses actions dans la même table** — l'audit reste unifié.
|
||||
|
||||
### 2.4 Auth par token Bearer
|
||||
|
||||
Fichier : `app/routers/public_api.py`. Déjà en place :
|
||||
- `POST /api/v1/token` génère un token `fd_<urlsafe>` (fonction du `user_tokens` de l'utilisateur connecté)
|
||||
- `verify_token(Authorization)` valide `Bearer <token>` contre la table `user_tokens`
|
||||
|
||||
Table `user_tokens(gitea_user_id, gitea_token)` — **attention** : `gitea_user_id` stocke en réalité
|
||||
l'**id local** de `users.id` (voir `SessionManager.store_token(user_id, ...)`). Donc la résolution
|
||||
token → user est directe : `SELECT gitea_user_id FROM user_tokens WHERE gitea_token = ?`.
|
||||
|
||||
### 2.5 Contexte agent
|
||||
|
||||
`ContextBuilder` (`app/services/context_builder.py`) collecte le contexte (page courante, mentions,
|
||||
workspace) — utile pour la resource MCP `flowdeck://context` si on veut l'exposer.
|
||||
|
||||
---
|
||||
|
||||
## 3. Positionnement {#3-positionnement}
|
||||
|
||||
Deux surfaces agentiques, complémentaires — **ne pas confondre** :
|
||||
|
||||
| | Agent interne (existant) | Serveur MCP (à créer) |
|
||||
|---|---|---|
|
||||
| **Direction** | L'utilisateur parle à l'agent **dans** FlowDeck | Un agent externe parle **à** FlowDeck depuis dehors |
|
||||
| **Orchestration** | `AgentEngine` (boucle ReAct, LLM) | Le **client** MCP orchestre (le serveur ne fait qu'exécuter des outils) |
|
||||
| **Interface** | Panneau HTML + SSE (`/api/agent/*`) | Protocole MCP (stdio ou Streamable HTTP) |
|
||||
| **Réutilise** | ToolRegistry, PermissionManager, audit | **Le même ToolRegistry, le même PermissionManager, le même audit** |
|
||||
| **Valeur** | Assistant intégré à l'UI | FlowDeck pilotable par Claude/Cursor/Hermes/scripts MCP |
|
||||
|
||||
Le serveur MCP **ne contient pas de LLM** : il exécute les outils demandés par le client. C'est le client
|
||||
(claude, cursor, openclaw…) qui décide quoi appeler. Le code de raisonnement n'est pas dupliqué.
|
||||
|
||||
---
|
||||
|
||||
## 4. Architecture cible {#4-architecture-cible}
|
||||
|
||||
```
|
||||
AGENTS EXTERNES (clients MCP)
|
||||
┌───────────────┬──────────────────┬──────────────────┐
|
||||
▼ ▼ ▼ ▼
|
||||
Claude Desktop Cursor CLI OpenClaw/Hermes npx mcp-remote
|
||||
(stdio local) (stdio local) (stdio / HTTP) (HTTP distant)
|
||||
│ │ │ │
|
||||
│ ┌─────────┴──────────┐ │ │
|
||||
│ ▼ ▼ ▼ ▼
|
||||
│ ┌─────────────────────────────────────────────┐
|
||||
│ │ app/mcp_server.py (FastMCP) │
|
||||
│ │ ─ stdio : python -m app.mcp_server │
|
||||
│ │ ─ HTTP : uvicorn (Streamable HTTP) │
|
||||
│ │ ├─ auth MCP (token fd_* / env var) │
|
||||
│ │ ├─ résolution user_id │
|
||||
│ │ └─ mise en correspondance outils MCP │
|
||||
│ └───────────────┬─────────────────────────────┘
|
||||
│ │ (mêmes fonctions que l'app)
|
||||
│ ┌───────────────▼─────────────────────────────┐
|
||||
│ │ ToolRegistry (22 outils) — INCHANGÉ │
|
||||
│ │ PermissionManager — INCHANGÉ │
|
||||
│ │ agent_actions (audit + undo) — INCHANGÉ │
|
||||
│ │ SessionManager.get_token(user_id) │
|
||||
│ └───────────────┬─────────────────────────────┘
|
||||
│ │
|
||||
│ ┌───────────┴────────────┐
|
||||
│ ▼ ▼
|
||||
│ SQLite (flowdeck.db) Gitea / GitHub API
|
||||
```
|
||||
|
||||
**Principe : zéro modification des services existants.** Le module MCP importe `app.services.tool_registry`
|
||||
et appelle les mêmes classes que l'agent interne. La seule chose nouvelle est la couche protocole.
|
||||
|
||||
---
|
||||
|
||||
## 5. Services offerts {#5-services-offerts}
|
||||
|
||||
Le serveur expose les **22 outils existants** (déjà présents dans `ToolRegistry`), groupés par service :
|
||||
|
||||
### Recherche & navigation
|
||||
| Outil MCP | Description |
|
||||
|---|---|
|
||||
| `search_workspace` | Recherche full-text (collections, pages, documents, workspaces) |
|
||||
| `read_workspaces` | Liste les espaces de travail accessibles et leur contenu |
|
||||
|
||||
### Lecture
|
||||
| Outil MCP | Description |
|
||||
|---|---|
|
||||
| `read_collection` | Schéma (propriétés + vues) + pages d'une collection |
|
||||
| `read_page` | Page de collection + valeurs + dépendances |
|
||||
| `read_document` | Document éditeur (titre, contenu, métadonnées) |
|
||||
| `read_gitea_issues` | Issues Gitea d'un repo (état, labels, milestones) |
|
||||
|
||||
### Écriture (avec snapshot undo)
|
||||
| Outil MCP | Description |
|
||||
|---|---|
|
||||
| `create_collection` | Crée une collection + vue par défaut |
|
||||
| `create_view` | Vue (table/board/calendar/gallery/list/timeline/gantt/chart/form/map/feed) |
|
||||
| `add_property` | Propriété typée |
|
||||
| `create_page` | Page de collection + valeurs |
|
||||
| `create_document` | Document éditeur dans un workspace (Markdown ou blocs) |
|
||||
| `update_page` | Titre / propriétés d'une page |
|
||||
| `write_blocks` | Contenu blocs d'un document |
|
||||
| `add_relation` | Relation entre collections (avec réciproque) |
|
||||
| `create_sub_item` | Sous-élément |
|
||||
| `add_dependency` | Dépendance entre pages |
|
||||
| `apply_template` | Page depuis un template |
|
||||
|
||||
### Gitea ↔ FlowDeck
|
||||
| Outil MCP | Description |
|
||||
|---|---|
|
||||
| `sync_gitea` | Synchronise les issues d'un repo vers une collection |
|
||||
| `create_gitea_issue` | Crée une issue dans un repo |
|
||||
|
||||
### Destructif (gated — voir §8)
|
||||
| Outil MCP | Description |
|
||||
|---|---|
|
||||
| `delete_document` | Corbeille (soft delete) |
|
||||
| `delete_page` / `delete_collection` | Suppression (dur, exige `confirm`) |
|
||||
|
||||
### Extensions possibles (plus tard)
|
||||
- **Resource MCP** `flowdeck://workspaces` et `flowdeck://collection/{id}` (le modèle resource MCP est
|
||||
naturel pour « lister mes espaces » sans appeler un outil).
|
||||
- **Prompts MCP** : templates « CR de réunion », « Sprint review » réutilisant les skills de l'agent interne.
|
||||
- **Notifications MCP** (logging/sampling) — à réserver pour plus tard, les outils couvrent 95 % des besoins.
|
||||
|
||||
---
|
||||
|
||||
## 6. Plan d'implémentation {#6-plan-dimplémentation}
|
||||
|
||||
### Étape 1 — Dépendance
|
||||
|
||||
Ajouter dans `requirements.txt` :
|
||||
|
||||
```
|
||||
mcp>=1.9,<2
|
||||
```
|
||||
|
||||
> ⚠️ **Piège version SDK** : le SDK officiel `mcp` est passé en **v2**, où `FastMCP` est renommé `MCPServer`
|
||||
> (`from mcp.server.mcpserver import MCPServer`) et les API ont changé (migration : `py.sdk.modelcontextprotocol.io/v2/migration`).
|
||||
> **Épingler `mcp>=1.9,<2`** : l'API FastMCP v1 est la plus documentée (la quasi-totalité des exemples
|
||||
> publics) et parfaitement stable. La migration vers v2 peut se faire plus tard, sans changer les outils.
|
||||
|
||||
### Étape 2 — Nouveau module `app/mcp_server.py`
|
||||
|
||||
Squelette de référence (les 22 outils suivent le même patron ; 3 représentatifs ci-dessous) :
|
||||
|
||||
```python
|
||||
"""FlowDeck — Serveur MCP (v1).
|
||||
|
||||
Réexpose le ToolRegistry existant comme serveur MCP.
|
||||
Aucune modification des services : mêmes classes, mêmes permissions, même audit.
|
||||
Transports : stdio (local) ou Streamable HTTP (distant) via --transport http.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
from app.db import get_conn
|
||||
from app.services.tool_registry import (
|
||||
ToolRegistry, SearchWorkspace, ReadCollection, CreateCollection,
|
||||
CreatePage, CreateDocument, CreateGiteaIssue, # ... + les 16 autres
|
||||
)
|
||||
|
||||
mcp = FastMCP("flowdeck")
|
||||
|
||||
# ── Résolution d'utilisateur ──────────────────────────────────────────────
|
||||
def resolve_user_id() -> int | None:
|
||||
"""stdio : env FLOWDECK_MCP_USER_ID (dev) ou FLOWDECK_MCP_TOKEN (résout via user_tokens)."""
|
||||
uid = os.environ.get("FLOWDECK_MCP_USER_ID")
|
||||
if uid:
|
||||
return int(uid)
|
||||
token = os.environ.get("FLOWDECK_MCP_TOKEN")
|
||||
if token:
|
||||
with get_conn() as conn:
|
||||
row = conn.execute(
|
||||
"SELECT gitea_user_id FROM user_tokens WHERE gitea_token=?", (token,)
|
||||
).fetchone()
|
||||
return row["gitea_user_id"] if row else None
|
||||
return None # mode admin sans authentification (usage local uniquement)
|
||||
|
||||
# ── Outils : wrapper mince sur ToolRegistry ───────────────────────────────
|
||||
async def _run(impl, args: dict) -> str:
|
||||
result = await impl.execute(args, user_id=resolve_user_id())
|
||||
return json.dumps({
|
||||
"status": result.status,
|
||||
"message": result.message,
|
||||
"data": result.data,
|
||||
"target": {"type": result.target_type, "id": result.target_id},
|
||||
}, ensure_ascii=False)
|
||||
|
||||
@mcp.tool()
|
||||
async def search_workspace(query: str) -> str:
|
||||
"""Recherche full-text dans tout FlowDeck (collections, pages, documents, workspaces)."""
|
||||
return await _run(SearchWorkspace(), {"query": query})
|
||||
|
||||
@mcp.tool()
|
||||
async def read_collection(collection_id: int) -> str:
|
||||
"""Lit le schéma (propriétés + vues) et les pages d'une collection."""
|
||||
return await _run(ReadCollection(), {"collection_id": collection_id})
|
||||
|
||||
@mcp.tool()
|
||||
async def create_collection(name: str, description: str = "", icon: str = "📋") -> str:
|
||||
"""Crée une collection avec sa vue par défaut."""
|
||||
return await _run(CreateCollection(), {"name": name, "description": description, "icon": icon})
|
||||
|
||||
# ... même patron pour create_page, create_document, create_view, add_property,
|
||||
# update_page, write_blocks, add_relation, create_sub_item, add_dependency,
|
||||
# apply_template, read_page, read_document, read_workspaces,
|
||||
# read_gitea_issues, sync_gitea, create_gitea_issue,
|
||||
# delete_document, delete_page, delete_collection (voir §8 pour ces 3-là)
|
||||
|
||||
# ── Écriture systématique dans le journal d'audit ─────────────────────────
|
||||
# Chaque outil MCP DOIT journaliser dans agent_actions (comme AgentEngine._log_action)
|
||||
# pour garder l'audit unifié et permettre le rollback via undo_action().
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
transport = sys.argv[1] if len(sys.argv) > 1 else "stdio"
|
||||
mcp.run(transport=transport) # "stdio" | "streamable-http"
|
||||
```
|
||||
|
||||
### Étape 3 — Auditer les actions MCP
|
||||
|
||||
Réutiliser le schéma `agent_actions` : insérer un enregistrement à chaque exécution d'outil
|
||||
(`tool_name`, `payload_json`, `result_json`, `status`, `undo_snapshot_json`, `executed_by=user_id`).
|
||||
Le rollback (`undo_action`) fonctionne ensuite à l'identique pour les actions faites par des agents externes.
|
||||
|
||||
### Étape 4 — Point d'entrée & lancement
|
||||
|
||||
```bash
|
||||
# stdio (Claude Desktop, Cursor, OpenClaw…) — lancé par le client lui-même
|
||||
FLOWDECK_MCP_USER_ID=1 python -m app.mcp_server
|
||||
|
||||
# HTTP (antémémoire: agents distants) — port par défaut 8123
|
||||
FLOWDECK_MCP_TOKEN=fd_xxx uvicorn app.mcp_server_http:app --port 8123 # ou mcp.run(transport="streamable-http")
|
||||
```
|
||||
|
||||
En Docker : ajouter une commande/second process au conteneur existant (même image, même volume SQLite)
|
||||
ou un service compose séparé partageant le même volume — la base SQLite WAL se partage sans problème
|
||||
avec le process principal (déjà le cas en dev local).
|
||||
|
||||
### Étape 5 — Documentation client dans le repo
|
||||
|
||||
Ajouter un fichier `docs/MCP_CLIENTS.md` (ou une section du présent guide, §9) avec les blocs de config
|
||||
pour chaque client.
|
||||
|
||||
---
|
||||
|
||||
## 7. Transport & configuration {#7-transport--configuration}
|
||||
|
||||
| Transport | Usage | Lancement | Auth |
|
||||
|---|---|---|---|
|
||||
| **stdio** | Agents locaux (Claude Desktop, Cursor, OpenClaw) | Le client spawn `python -m app.mcp_server` | Env `FLOWDECK_MCP_USER_ID` / `FLOWDECK_MCP_TOKEN` |
|
||||
| **Streamable HTTP** | Agents distants / multi-clients | `uvicorn` sur `MCP_PORT` (défaut 8123) | Header `Authorization: Bearer fd_*` |
|
||||
|
||||
Variables d'environnement (à ajouter à `.env` / `app/config.py`) :
|
||||
|
||||
```
|
||||
MCP_ENABLED=true
|
||||
MCP_PORT=8123
|
||||
MCP_MAX_TOKENS_HISTORY=50 # contrôle de charge côté serveur (optionnel)
|
||||
FLOWDECK_MCP_TOKEN= # généré via POST /api/v1/token ou manuellement
|
||||
```
|
||||
|
||||
> **Streamable HTTP (spéc. 2025-03-26+)** remplace l'ancien SSE : le SDK FastMCP le gère nativement via
|
||||
> `mcp.run(transport="streamable-http")`. C'est le protocole utilisé par Notion (`mcp.notion.com/mcp`).
|
||||
|
||||
---
|
||||
|
||||
## 8. Sécurité {#8-sécurité}
|
||||
|
||||
1. **Auth** — HTTP : `Bearer fd_*` validé contre `user_tokens` (pattern de `public_api.verify_token`).
|
||||
stdio : variable d'env obligatoire ; refuser de démarrer sans résolution d'utilisateur en dehors du
|
||||
mode local explicite (`FLOWDECK_MCP_ALLOW_ANON=1` uniquement en dev).
|
||||
2. **Permissions** — chaque appel passe par `PermissionManager.assert_can(tool, args, workspace_id, ...)`
|
||||
comme pour l'agent interne. Un agent externe ne voit/ne modifie **que** ce que son utilisateur peut
|
||||
voir/modifier (pas de contournement MCP — même règle que Notion : *« MCP does not bypass Notion permissions »*).
|
||||
3. **Outils destructifs** — `delete_document`, `delete_page`, `delete_collection` : **non exposés par défaut**
|
||||
ou exigeant un paramètre explicite `confirm: true` + `approval_mode == "confirm"`. Recommandation :
|
||||
activables par env `FLOWDECK_MCP_ALLOW_DESTRUCTIVE=true`, désactivé par défaut.
|
||||
4. **Audit** — 100 % des actions MCP journalisées dans `agent_actions` (qui, quoi, quand, quel user,
|
||||
snapshot undo) → consultable depuis l'UI agent et rollback possible.
|
||||
5. **Rate limiting** — réutiliser le middleware existant (`slowapi`) côté HTTP ; côté stdio le client
|
||||
contrôle le débit.
|
||||
6. **Réseau** — en HTTP, ne pas exposer directement : reverse-proxy avec TLS (Traefik/Caddy/Nginx) et
|
||||
restriction IP si l'usage est interne au homelab. Le token `fd_*` transite en clair sinon.
|
||||
|
||||
---
|
||||
|
||||
## 9. Configuration des clients {#9-configuration-des-clients}
|
||||
|
||||
### Claude Desktop — `claude_desktop_config.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"flowdeck": {
|
||||
"command": "python",
|
||||
"args": ["-m", "app.mcp_server"],
|
||||
"cwd": "/home/bruno/workspace/flowdeck",
|
||||
"env": { "FLOWDECK_MCP_USER_ID": "1" }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Cursor — `.cursor/mcp.json` (même structure)
|
||||
|
||||
### OpenClaw / Hermes — `config.yaml` (client MCP natif)
|
||||
|
||||
```yaml
|
||||
mcp:
|
||||
servers:
|
||||
flowdeck:
|
||||
command: python
|
||||
args: ["-m", "app.mcp_server"]
|
||||
cwd: /home/bruno/workspace/flowdeck
|
||||
env: { FLOWDECK_MCP_USER_ID: "1" }
|
||||
```
|
||||
|
||||
### Distant (HTTP) — n'importe quel client MCP
|
||||
|
||||
```bash
|
||||
# via mcp-remote (bridge stdio→HTTP)
|
||||
npx mcp-remote http://flowdeck.lab.home:8123/mcp --header "Authorization: Bearer fd_xxx"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Tests & vérification {#10-tests--vérification}
|
||||
|
||||
1. **Inspector officiel** : `mcp dev app/mcp_server.py` (SDK v1) — UI web pour lister les outils,
|
||||
exécuter chaque outil, vérifier schémas et erreurs.
|
||||
2. **Test pytest** (`tests/test_mcp_server.py`) : démarrer le serveur en stdio, client `mcp.client.stdio`,
|
||||
`tools/list` doit renvoyer ≥ 20 outils avec les bons `inputSchema` ; `call_tool("create_collection")`
|
||||
crée réellement la collection (vérifier en DB), `call_tool("delete_collection")` est refusé sans `confirm`.
|
||||
3. **Vérification d'audit** : après un appel MCP, une ligne `agent_actions` doit exister avec
|
||||
`executed_by` = l'utilisateur résolu.
|
||||
4. **CI Gitea Actions** : ajouter ces tests à la pipeline existante (pytest + ruff).
|
||||
|
||||
---
|
||||
|
||||
## 11. Version & roadmap {#11-version--roadmap}
|
||||
|
||||
Proposer une entrée en roadmap (le projet est à v5.x, `realtime` en v5.13.0) :
|
||||
|
||||
> **v5.14.0 — Serveur MCP** : exposition du ToolRegistry via MCP (stdio + Streamable HTTP),
|
||||
> auth par token `fd_*`, audit unifié `agent_actions`, outils destructifs gated,
|
||||
> guide client + tests.
|
||||
|
||||
Étapes de livraison : (1) squelette + inspector, (2) audit + rollback, (3) transport HTTP + auth,
|
||||
(4) configs clients + docs, (5) CI.
|
||||
|
||||
---
|
||||
|
||||
## 12. Liens & références {#12-liens--références}
|
||||
|
||||
- Spec MCP : https://modelcontextprotocol.io
|
||||
- SDK Python officiel : https://github.com/modelcontextprotocol/python-sdk (épingler `<2` pour FastMCP v1)
|
||||
- Notion MCP (modèle de référence, déjà documenté dans ce repo) : `docs/Guide_Complet_Notion_AI.md`
|
||||
- Code à réutiliser : `app/services/tool_registry.py` · `app/services/permission_manager.py` ·
|
||||
`app/routers/public_api.py` (auth token) · `app/services/agent_engine.py` (`agent_actions` + undo)
|
||||
- Guide agent interne existant : `docs/Flowdeck_Agent_integration.md`
|
||||
Reference in New Issue
Block a user