# Plan d'Intégration MCP + Agent Vocal ## Objectif Transformer AISSIA en "Claude Code vocal" : un assistant qui peut utiliser des tools (internes + MCP) pour accomplir des tâches, piloté par la voix. ## Architecture Cible ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ AISSIA - Agent Vocal │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────┐ ┌──────────┐ ┌─────────────────────────────────────┐ │ │ │ Micro │───►│ STT │───►│ LLMService │ │ │ └──────────┘ │ (Whisper)│ │ (Agentic Loop) │ │ │ └──────────┘ │ │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ ToolRegistry │ │ │ │ │ │ │ │ │ │ │ │ ┌───────────────────────┐ │ │ │ │ │ │ │ Internal Tools │ │ │ │ │ │ │ │ (via GroveEngine) │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ • get_schedule │ │ │ │ │ │ │ │ • start_break │ │ │ │ │ │ │ │ • get_focus_stats │ │ │ │ │ │ │ │ • save_note │ │ │ │ │ │ │ │ • query_history │ │ │ │ │ │ │ └───────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ ┌───────────────────────┐ │ │ │ │ │ │ │ MCP Tools │ │ │ │ │ │ │ │ (via MCPClient) │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ • read_file │ │ │ │ │ │ │ │ • write_file │ │ │ │ │ │ │ │ • list_directory │ │ │ │ │ │ │ │ • web_search │ │ │ │ │ │ │ │ • fetch_url │ │ │ │ │ │ │ └───────────────────────┘ │ │ │ │ │ └─────────────────────────────┘ │ │ │ │ │ │ │ └──────────────────┬──────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────┐ ┌──────────┐ ┌─────────────────────────────────────┐ │ │ │ Speaker │◄───│ TTS │◄───│ Response Text │ │ │ └──────────┘ │ (espeak) │ └─────────────────────────────────────┘ │ │ └──────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ COMMUNICATION INTERNE (GroveEngine IIO) ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Scheduler │ │ Monitoring │ │ Storage │ │ Voice │ │ Module │ │ Module │ │ Module │ │ Module │ ├──────────────┤ ├──────────────┤ ├──────────────┤ ├──────────────┤ │ │ │ │ │ │ │ │ │ • tasks │ │ • app usage │ │ • sessions │ │ • TTS queue │ │ • breaks │ │ • focus time │ │ • notes │ │ • STT events │ │ • hyperfocus │ │ • idle │ │ • history │ │ │ │ │ │ │ │ │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ └────────────────────┴────────────────────┴────────────────────┘ │ IIO Pub/Sub │ ┌───────────────┴───────────────┐ │ LLMService │ │ (écoute les tool:* topics) │ └───────────────────────────────┘ ``` ## Phases d'Implémentation ### Phase 1 : Tools Internes via IIO **Objectif** : Les modules GroveEngine exposent leurs fonctionnalités comme tools LLM. **Fichiers à créer/modifier** : - `src/shared/tools/InternalTools.hpp` - Définitions des tools internes - `src/shared/tools/InternalTools.cpp` - Implémentation - `src/services/LLMService.cpp` - Enregistrement des tools **Tools à implémenter** : | Tool | Module Source | Description | |------|---------------|-------------| | `get_current_task` | SchedulerModule | Retourne la tâche en cours | | `list_tasks` | SchedulerModule | Liste toutes les tâches planifiées | | `start_task` | SchedulerModule | Démarre une tâche par ID | | `complete_task` | SchedulerModule | Marque une tâche comme terminée | | `start_break` | SchedulerModule | Déclenche une pause | | `get_focus_stats` | MonitoringModule | Stats de focus (temps, apps) | | `get_current_app` | MonitoringModule | App actuellement active | | `save_note` | StorageModule | Sauvegarde une note | | `query_notes` | StorageModule | Recherche dans les notes | | `get_session_history` | StorageModule | Historique des sessions | | `speak` | VoiceModule | Fait parler l'assistant | **Pattern d'implémentation** : ```cpp // Le tool envoie une requête via IIO et attend la réponse json InternalTools::executeGetCurrentTask(const json& input) { // 1. Créer la requête auto request = std::make_unique("request"); request->setString("action", "get_current_task"); // 2. Publier et attendre réponse (sync via promise/future) auto response = m_ioBridge->requestAndWait("scheduler:query", std::move(request), 1000); // 3. Convertir en JSON pour le LLM return { {"task_id", response->getString("task_id", "")}, {"task_name", response->getString("task_name", "")}, {"duration_minutes", response->getInt("duration_minutes", 0)} }; } ``` ### Phase 2 : Client MCP **Objectif** : Se connecter à des serveurs MCP externes (filesystem, brave-search, etc.) **Fichiers à créer** : - `src/shared/mcp/MCPClient.hpp` - Interface client MCP - `src/shared/mcp/MCPClient.cpp` - Implémentation - `src/shared/mcp/MCPTransport.hpp` - Transport stdio/SSE - `src/shared/mcp/MCPTypes.hpp` - Types MCP (Tool, Resource, etc.) **Protocole MCP simplifié** : ``` Client Server (ex: filesystem) │ │ │──── initialize ─────────────────►│ │◄─── initialized (capabilities) ──│ │ │ │──── tools/list ─────────────────►│ │◄─── tools (read_file, etc.) ─────│ │ │ │──── tools/call ─────────────────►│ │ {name: "read_file", │ │ arguments: {path: "..."}} │ │◄─── result ──────────────────────│ │ {content: "..."} │ │ │ ``` **Transport stdio** : ```cpp class StdioTransport : public IMCPTransport { public: StdioTransport(const std::string& command, const std::vector& args) { // Fork + exec le serveur MCP // Rediriger stdin/stdout pour JSON-RPC } json sendRequest(const std::string& method, const json& params) { json request = { {"jsonrpc", "2.0"}, {"id", m_nextId++}, {"method", method}, {"params", params} }; // Écrire sur stdin du process write(request.dump() + "\n"); // Lire la réponse sur stdout return json::parse(readLine()); } }; ``` **Configuration MCP** : ```json // config/mcp.json { "servers": { "filesystem": { "command": "npx", "args": ["-y", "@anthropic-ai/mcp-server-filesystem", "/home/user/documents"], "enabled": true }, "brave-search": { "command": "npx", "args": ["-y", "@anthropic-ai/mcp-server-brave-search"], "env": { "BRAVE_API_KEY": "${BRAVE_API_KEY}" }, "enabled": true }, "fetch": { "command": "npx", "args": ["-y", "@anthropic-ai/mcp-server-fetch"], "enabled": true } } } ``` ### Phase 3 : Unification ToolRegistry **Objectif** : Le ToolRegistry agrège tools internes + MCP de façon transparente. **Modification de LLMService** : ```cpp void LLMService::initializeTools() { // 1. Tools internes (via IIO) m_internalTools = std::make_unique(m_io); for (const auto& tool : m_internalTools->getTools()) { m_toolRegistry.registerTool(tool); } // 2. Tools MCP (via MCPClient) m_mcpClient = std::make_unique(); m_mcpClient->loadConfig("config/mcp.json"); m_mcpClient->connectAll(); for (const auto& tool : m_mcpClient->listAllTools()) { m_toolRegistry.registerTool( tool.name, tool.description, tool.inputSchema, [this, name = tool.name](const json& input) { return m_mcpClient->callTool(name, input); } ); } m_logger->info("Tools loaded: {} internal, {} MCP", m_internalTools->size(), m_mcpClient->toolCount()); } ``` ### Phase 4 : Tests **Tests unitaires** : - `tests/test_internal_tools.cpp` - Mock IIO, vérifier tool execution - `tests/test_mcp_client.cpp` - Mock server, vérifier protocole - `tests/test_tool_registry.cpp` - Vérifier aggregation **Test d'intégration** : ```cpp // tests/integration/test_agentic_loop.cpp TEST_CASE("Agentic loop with tools") { LLMService service; service.initialize(io); service.loadConfig("config/llm.json"); // Simuler une query qui nécessite des tools auto result = service.query("Quelle tâche je fais en ce moment ?"); // Vérifier que le tool get_current_task a été appelé REQUIRE(result.contains("task")); } ``` ## Fichiers à Créer ``` src/ ├── shared/ │ ├── tools/ │ │ ├── InternalTools.hpp # Tools internes (IIO) │ │ ├── InternalTools.cpp │ │ └── IOBridge.hpp # Request/response sync via IIO │ └── mcp/ │ ├── MCPClient.hpp # Client MCP principal │ ├── MCPClient.cpp │ ├── MCPTransport.hpp # Interface transport │ ├── StdioTransport.hpp # Transport stdio (fork/exec) │ ├── StdioTransport.cpp │ └── MCPTypes.hpp # Tool, Resource, etc. ├── services/ │ └── LLMService.cpp # Modifier pour init tools └── modules/ ├── SchedulerModule.cpp # Ajouter handlers pour tools ├── MonitoringModule.cpp └── StorageModule.cpp config/ └── mcp.json # Configuration serveurs MCP tests/ ├── test_internal_tools.cpp ├── test_mcp_client.cpp └── integration/ └── test_agentic_loop.cpp ``` ## Ordre d'Implémentation 1. **IOBridge** - Request/response synchrone via IIO 2. **InternalTools** - Définition et implémentation des tools 3. **Modules handlers** - Ajouter la gestion des requêtes tools dans chaque module 4. **Test internal tools** - Vérifier que ça marche 5. **MCPTypes** - Types de base MCP 6. **StdioTransport** - Fork/exec + communication JSON-RPC 7. **MCPClient** - Orchestration des serveurs 8. **Test MCP** - Vérifier avec un vrai serveur (filesystem) 9. **Unification** - Merger dans LLMService 10. **Test intégration** - End-to-end ## Estimation Temps | Phase | Temps estimé | |-------|--------------| | Phase 1 : Tools Internes | 2-3h | | Phase 2 : Client MCP | 2-3h | | Phase 3 : Unification | 1h | | Phase 4 : Tests | 1-2h | | **Total** | **6-9h** | ## Dépendances - `nlohmann/json` - Déjà présent - `spdlog` - Déjà présent - Node.js/npx - Pour les serveurs MCP (optionnel, on peut aussi implémenter nos propres serveurs en C++) ## Risques et Mitigations | Risque | Mitigation | |--------|------------| | Fork/exec complexe sur Windows | Utiliser `_popen` ou process lib cross-platform | | Timeout sur tools lents | Configurable per-tool, default 30s | | Serveur MCP crash | Reconnect automatique, fallback graceful | | Trop de tools = confusion LLM | Grouper par namespace, limiter à ~20 tools |