feat: Phase 8 - MCP Server integration with Claude Code

Expose AISSIA as MCP Server to integrate with Claude Code and other MCP clients.

**New Infrastructure**:
- MCPServerTools: Bridge between MCP Server and AISSIA services
- Synchronous service methods for blocking MCP calls
- 13 total tools exposed (5 AISSIA core + 8 filesystem)

**Priority Tool**:
- chat_with_aissia: Dialogue with AISSIA's AI assistant (Claude Sonnet 4)

**AISSIA Core Tools** (5):
1. chat_with_aissia - AI conversation with Claude Sonnet 4
2. transcribe_audio - STT file transcription (stub)
3. text_to_speech - TTS file output (stub)
4. save_memory - Persistent storage (stub)
5. search_memories - Memory search (stub)

**Changes**:
- src/shared/tools/MCPServerTools.{hpp,cpp}: New tool handlers for AISSIA services
- src/services/LLMService: Added sendMessageSync() for blocking calls
- src/services/VoiceService: Added loadConfig(), transcribeFileSync(), textToSpeechSync()
- src/main.cpp: Refactored runMCPServer() to instantiate services and register AISSIA tools
- CMakeLists.txt: Added MCPServerTools to AissiaTools library

**Documentation**:
- docs/CLAUDE_CODE_INTEGRATION.md: Complete integration guide
- config/README_MCP.md: Quick setup instructions
- config/claude_code_mcp_config.json: Example MCP configuration

**Usage**:
```bash
./aissia --mcp-server
```

**Limitations (MVP)**:
- STT/TTS file operations not fully implemented (engines need file support)
- Storage sync methods return "not implemented" (async pub/sub only)
- No hot-reload modules in MCP mode

**Next Steps** (Phase 8.1-8.4):
- Complete STT/TTS sync methods
- Implement StorageService sync API
- Add advanced tools (schedule_task, get_focus_stats)
- Multi-modal support (vision, PDF parsing)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
StillHammer 2025-11-30 17:42:15 +08:00
parent d7971e0c34
commit cb938500cd
11 changed files with 1335 additions and 4 deletions

View File

@ -83,10 +83,11 @@ if(OPENSSL_FOUND)
target_compile_definitions(AissiaLLM PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT)
endif()
# Tools Library (Internal tools + FileSystem tools + MCP client + MCP server)
# Tools Library (Internal tools + FileSystem tools + MCP client + MCP server + MCP Server Tools)
add_library(AissiaTools STATIC
src/shared/tools/InternalTools.cpp
src/shared/tools/FileSystemTools.cpp
src/shared/tools/MCPServerTools.cpp
src/shared/mcp/StdioTransport.cpp
src/shared/mcp/MCPClient.cpp
src/shared/mcp/MCPServer.cpp

305
config/README_MCP.md Normal file
View File

@ -0,0 +1,305 @@
# AISSIA MCP Configuration for Claude Code
This directory contains an example MCP (Model Context Protocol) configuration for integrating AISSIA with Claude Code.
## Quick Setup
### 1. Locate Claude Code MCP Settings
The MCP configuration file location depends on your operating system:
**Windows**:
```
%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json
```
Full path example:
```
C:\Users\YourUsername\AppData\Roaming\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json
```
**macOS**:
```
~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json
```
**Linux**:
```
~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json
```
### 2. Copy Configuration
Copy the contents of `claude_code_mcp_config.json` to the Claude Code MCP settings file.
**Important**: Update the `command` path to point to your actual AISSIA executable:
```json
{
"mcpServers": {
"aissia": {
"command": "C:\\path\\to\\your\\aissia\\build\\aissia.exe",
"args": ["--mcp-server"],
"disabled": false
}
}
}
```
### 3. Restart Claude Code
Restart VS Code (or reload window: `Ctrl+Shift+P` → "Developer: Reload Window") to apply the changes.
### 4. Verify Integration
Open Claude Code and check that AISSIA tools are available:
```
You: Can you list the available MCP servers?
Claude: I have access to the following MCP servers:
- aissia: 13 tools available
```
## Available Tools
Once configured, Claude will have access to these 13 AISSIA tools:
### AISSIA Core (5 tools)
1. **chat_with_aissia** ⭐ - Dialogue with AISSIA's AI assistant (Claude Sonnet 4)
2. **transcribe_audio** - Transcribe audio files to text
3. **text_to_speech** - Convert text to speech audio files
4. **save_memory** - Save notes to AISSIA's persistent storage
5. **search_memories** - Search through saved memories
### File System (8 tools)
6. **read_file** - Read file contents
7. **write_file** - Write content to files
8. **list_directory** - List files in a directory
9. **search_files** - Search for files by pattern
10. **file_exists** - Check if a file exists
11. **create_directory** - Create directories
12. **delete_file** - Delete files
13. **move_file** - Move or rename files
## Configuration Options
### Basic Configuration
```json
{
"mcpServers": {
"aissia": {
"command": "path/to/aissia.exe",
"args": ["--mcp-server"],
"disabled": false
}
}
}
```
### With Auto-Approval
To skip confirmation prompts for specific tools:
```json
{
"mcpServers": {
"aissia": {
"command": "path/to/aissia.exe",
"args": ["--mcp-server"],
"disabled": false,
"alwaysAllow": ["chat_with_aissia", "read_file", "write_file"]
}
}
}
```
### Disable Server
To temporarily disable AISSIA without removing the configuration:
```json
{
"mcpServers": {
"aissia": {
"command": "path/to/aissia.exe",
"args": ["--mcp-server"],
"disabled": true // <-- Set to true
}
}
}
```
## Prerequisites
Before running AISSIA in MCP server mode, ensure these config files exist:
### config/ai.json
```json
{
"provider": "claude",
"api_key": "sk-ant-api03-...",
"model": "claude-sonnet-4-20250514",
"max_iterations": 10,
"system_prompt": "Tu es AISSIA, un assistant personnel intelligent..."
}
```
### config/storage.json
```json
{
"database_path": "./data/aissia.db",
"journal_mode": "WAL",
"busy_timeout_ms": 5000
}
```
### config/voice.json (optional)
```json
{
"tts": {
"enabled": true,
"rate": 0,
"volume": 80
},
"stt": {
"active_mode": {
"enabled": false
}
}
}
```
## Testing MCP Server
You can test the MCP server independently before integrating with Claude Code:
```bash
# Test tools/list
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | ./build/aissia.exe --mcp-server
# Test chat_with_aissia tool
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"chat_with_aissia","arguments":{"message":"What time is it?"}}}' | ./build/aissia.exe --mcp-server
```
## Troubleshooting
### "Server not found" or "Connection failed"
1. Verify the `command` path is correct and points to `aissia.exe`
2. Make sure AISSIA compiles successfully: `cmake --build build`
3. Test running `./build/aissia.exe --mcp-server` manually
### "LLMService not initialized"
AISSIA requires `config/ai.json` with a valid Claude API key. Check:
1. File exists: `config/ai.json`
2. API key is valid: `"api_key": "sk-ant-api03-..."`
3. Provider is set: `"provider": "claude"`
### "Tool execution failed"
Some tools have limited functionality in Phase 8 MVP:
- `transcribe_audio` - Not fully implemented yet (STT file support needed)
- `text_to_speech` - Not fully implemented yet (TTS file output needed)
- `save_memory` - Not fully implemented yet (Storage sync methods needed)
- `search_memories` - Not fully implemented yet (Storage sync methods needed)
These will be completed in Phase 8.1 and 8.2.
### Server starts but tools don't appear
1. Check Claude Code logs: `Ctrl+Shift+P` → "Developer: Open Extension Logs"
2. Look for MCP server initialization errors
3. Verify JSON syntax in the MCP configuration file
## Example Use Cases
### 1. Ask AISSIA for Help
```
You: Use chat_with_aissia to ask "What are my top productivity patterns?"
Claude: [calls chat_with_aissia tool]
AISSIA: Based on your activity data, your most productive hours are 9-11 AM...
```
### 2. File Operations + AI
```
You: Read my TODO.md file and ask AISSIA to prioritize the tasks
Claude: [calls read_file("TODO.md")]
Claude: [calls chat_with_aissia with task list]
AISSIA: Here's a prioritized version based on urgency and dependencies...
```
### 3. Voice Transcription (future)
```
You: Transcribe meeting-notes.wav to text
Claude: [calls transcribe_audio("meeting-notes.wav")]
Result: "Welcome to the team meeting. Today we're discussing..."
```
## Advanced Configuration
### Multiple MCP Servers
You can configure multiple MCP servers alongside AISSIA:
```json
{
"mcpServers": {
"aissia": {
"command": "C:\\path\\to\\aissia\\build\\aissia.exe",
"args": ["--mcp-server"],
"disabled": false
},
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "C:\\Users"],
"disabled": false
},
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"disabled": false,
"env": {
"BRAVE_API_KEY": "your-brave-api-key"
}
}
}
}
```
### Environment Variables
Pass environment variables to AISSIA:
```json
{
"mcpServers": {
"aissia": {
"command": "C:\\path\\to\\aissia\\build\\aissia.exe",
"args": ["--mcp-server"],
"disabled": false,
"env": {
"AISSIA_LOG_LEVEL": "debug",
"CLAUDE_API_KEY": "sk-ant-api03-..."
}
}
}
}
```
## References
- **Full Documentation**: `docs/CLAUDE_CODE_INTEGRATION.md`
- **MCP Specification**: https://github.com/anthropics/mcp
- **Claude Code Extension**: https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev
## Support
For issues or questions:
1. Check the full documentation: `docs/CLAUDE_CODE_INTEGRATION.md`
2. Review logs: AISSIA writes to stderr in MCP mode
3. Test manually: `./build/aissia.exe --mcp-server` and send JSON-RPC requests

View File

@ -0,0 +1,10 @@
{
"mcpServers": {
"aissia": {
"command": "C:\\Users\\alexi\\Documents\\projects\\aissia\\build\\aissia.exe",
"args": ["--mcp-server"],
"disabled": false,
"alwaysAllow": []
}
}
}

View File

@ -0,0 +1,449 @@
# AISSIA - Claude Code Integration (Phase 8)
## Overview
AISSIA can now be exposed as an **MCP Server** (Model Context Protocol) to integrate with Claude Code and other MCP-compatible clients. This allows Claude to use AISSIA's capabilities as tools during conversations.
**Mode MCP Server**: `./aissia --mcp-server`
This mode exposes AISSIA's services via JSON-RPC 2.0 over stdio, following the MCP specification.
## Available Tools
AISSIA exposes **13 tools** total:
### 1. AISSIA Core Tools (Priority)
#### `chat_with_aissia` ⭐ **PRIORITY**
Dialogue with AISSIA's built-in AI assistant (Claude Sonnet 4). Send a message and get an intelligent response with access to AISSIA's knowledge and capabilities.
**Input**:
```json
{
"message": "string (required) - Message to send to AISSIA",
"conversation_id": "string (optional) - Conversation ID for continuity",
"system_prompt": "string (optional) - Custom system prompt"
}
```
**Output**:
```json
{
"response": "AISSIA's response text",
"conversation_id": "conversation-id",
"tokens": 1234,
"iterations": 2
}
```
**Example use case**: "Hey AISSIA, can you analyze my focus patterns this week?"
#### `transcribe_audio`
Transcribe audio file to text using Speech-to-Text engines (Whisper.cpp, OpenAI Whisper API, Google Speech).
**Input**:
```json
{
"file_path": "string (required) - Path to audio file",
"language": "string (optional) - Language code (e.g., 'fr', 'en'). Default: 'fr'"
}
```
**Output**:
```json
{
"text": "Transcribed text from audio",
"file": "/path/to/audio.wav",
"language": "fr"
}
```
**Status**: ⚠️ Not yet implemented - requires STT service file transcription support
#### `text_to_speech`
Convert text to speech audio file using Text-to-Speech synthesis. Generates audio in WAV format.
**Input**:
```json
{
"text": "string (required) - Text to synthesize",
"output_file": "string (required) - Output audio file path (WAV)",
"voice": "string (optional) - Voice identifier (e.g., 'fr-fr', 'en-us'). Default: 'fr-fr'"
}
```
**Output**:
```json
{
"success": true,
"file": "/path/to/output.wav",
"voice": "fr-fr"
}
```
**Status**: ⚠️ Not yet implemented - requires TTS engine file output support
#### `save_memory`
Save a note or memory to AISSIA's persistent storage. Memories can be tagged and searched later.
**Input**:
```json
{
"title": "string (required) - Memory title",
"content": "string (required) - Memory content",
"tags": ["array of strings (optional) - Tags for categorization"]
}
```
**Output**:
```json
{
"id": "memory-uuid",
"title": "Meeting notes",
"timestamp": "2025-01-30T10:00:00Z"
}
```
**Status**: ⚠️ Not yet implemented - requires StorageService sync methods
#### `search_memories`
Search through saved memories and notes in AISSIA's storage. Returns matching memories with relevance scores.
**Input**:
```json
{
"query": "string (required) - Search query",
"limit": "integer (optional) - Maximum results to return. Default: 10"
}
```
**Output**:
```json
{
"results": [
{
"id": "memory-uuid",
"title": "Meeting notes",
"content": "...",
"score": 0.85,
"tags": ["work", "meeting"]
}
],
"count": 5
}
```
**Status**: ⚠️ Not yet implemented - requires StorageService sync methods
### 2. File System Tools (8 tools)
- `read_file` - Read a file from the filesystem
- `write_file` - Write content to a file
- `list_directory` - List files in a directory
- `search_files` - Search for files by pattern
- `file_exists` - Check if a file exists
- `create_directory` - Create a new directory
- `delete_file` - Delete a file
- `move_file` - Move or rename a file
These tools provide Claude with direct filesystem access to work with files on your system.
## Installation for Claude Code
### 1. Configure Claude Code MCP
Create or edit your Claude Code MCP configuration file:
**Windows**: `%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json`
**macOS/Linux**: `~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
Add AISSIA as an MCP server:
```json
{
"mcpServers": {
"aissia": {
"command": "C:\\path\\to\\aissia\\build\\aissia.exe",
"args": ["--mcp-server"],
"disabled": false
}
}
}
```
**Note**: Replace `C:\\path\\to\\aissia\\build\\aissia.exe` with the actual path to your compiled AISSIA executable.
### 2. Verify Configuration
Restart Claude Code (or VS Code) to reload the MCP configuration.
Claude should now have access to all 13 AISSIA tools during conversations.
### 3. Test Integration
In Claude Code, try:
```
"Can you use the chat_with_aissia tool to ask AISSIA what time it is?"
```
Claude will call the `chat_with_aissia` tool, which internally uses AISSIA's LLM service to process the query.
## Architecture
### Synchronous Mode (MCP Server)
When running as an MCP server, AISSIA uses **synchronous blocking calls** instead of the async pub/sub architecture used in normal mode:
```cpp
// Normal mode (async)
io->publish("llm:request", data);
// ... wait for response on "llm:response" topic
// MCP mode (sync)
auto response = llmService->sendMessageSync(message, conversationId);
// immediate result
```
This is necessary because:
1. MCP protocol expects immediate JSON-RPC responses
2. No event loop in MCP server mode (stdin/stdout blocking I/O)
3. Simplifies integration with external tools
### Service Integration
```
MCPServer (stdio JSON-RPC)
MCPServerTools (tool handlers)
Services (sync methods)
├── LLMService::sendMessageSync()
├── VoiceService::transcribeFileSync()
├── VoiceService::textToSpeechSync()
└── StorageService (stub implementations)
```
### Tool Registry
All tools are registered in a central `ToolRegistry`:
```cpp
ToolRegistry registry;
// 1. Internal tools (get_current_time)
registry.registerTool("get_current_time", ...);
// 2. FileSystem tools (8 tools)
for (auto& toolDef : FileSystemTools::getToolDefinitions()) {
registry.registerTool(toolDef);
}
// 3. AISSIA tools (5 tools)
MCPServerTools aissiaTools(llmService, storageService, voiceService);
for (const auto& toolDef : aissiaTools.getToolDefinitions()) {
registry.registerTool(toolDef);
}
```
Total: **13 tools**
## Configuration Files
AISSIA MCP Server requires these config files (same as normal mode):
- `config/ai.json` - LLM provider configuration (Claude API key)
- `config/storage.json` - Database path and settings
- `config/voice.json` - TTS/STT engine settings
**Important**: Make sure these files are present before running `--mcp-server` mode.
## Limitations (Phase 8 MVP)
1. **STT/TTS file operations**: `transcribe_audio` and `text_to_speech` are not fully implemented yet
- STT service needs file transcription support (currently only streaming)
- TTS engine needs file output support (currently only direct playback)
2. **Storage sync methods**: `save_memory` and `search_memories` return "not implemented" errors
- StorageService needs `saveMemorySync()` and `searchMemoriesSync()` methods
- Current storage only works via async pub/sub
3. **No hot-reload**: MCP server mode doesn't load hot-reloadable modules
- Only services and tools are available
- No SchedulerModule, MonitoringModule, etc.
4. **Single-threaded**: MCP server runs synchronously on main thread
- LLMService worker thread still runs for agentic loops
- But overall server is blocking on stdin
## Roadmap
### Phase 8.1 - Complete STT/TTS Sync Methods
- [ ] Implement `VoiceService::transcribeFileSync()` using STT engines
- [ ] Implement `VoiceService::textToSpeechSync()` with file output
- [ ] Test audio file transcription via MCP
### Phase 8.2 - Storage Sync Methods
- [ ] Implement `StorageService::saveMemorySync()`
- [ ] Implement `StorageService::searchMemoriesSync()`
- [ ] Add vector embeddings for semantic search
### Phase 8.3 - Advanced Tools
- [ ] `schedule_task` - Add tasks to AISSIA's scheduler
- [ ] `get_focus_stats` - Retrieve hyperfocus detection stats
- [ ] `list_active_apps` - Get current monitored applications
- [ ] `send_notification` - Trigger system notifications
### Phase 8.4 - Multi-Modal Support
- [ ] Image input for LLM (Claude vision)
- [ ] PDF/document parsing tools
- [ ] Web scraping integration
## Use Cases
### 1. AI Assistant Collaboration
Claude Code can delegate complex reasoning tasks to AISSIA:
```
Claude: "I need to analyze user behavior patterns. Let me ask AISSIA."
→ calls chat_with_aissia("Analyze recent focus patterns")
AISSIA: "Based on monitoring data, user has 3 hyperfocus sessions daily averaging 2.5 hours..."
```
### 2. Voice Transcription Workflow
```
Claude: "Transcribe meeting-2025-01-30.wav"
→ calls transcribe_audio(file_path="meeting-2025-01-30.wav", language="en")
→ calls write_file(path="transcript.txt", content=result)
```
### 3. Knowledge Management
```
Claude: "Save this important insight to AISSIA's memory"
→ calls save_memory(
title="Project architecture decision",
content="We decided to use hot-reload modules for business logic...",
tags=["architecture", "project"]
)
```
### 4. File + AI Operations
```
Claude: "Read todos.md, ask AISSIA to prioritize tasks, update file"
→ calls read_file("todos.md")
→ calls chat_with_aissia("Prioritize these tasks: ...")
→ calls write_file("todos-prioritized.md", content=...)
```
## Development
### Adding New Tools
1. **Declare tool in MCPServerTools.hpp**:
```cpp
json handleNewTool(const json& input);
```
2. **Implement in MCPServerTools.cpp**:
```cpp
json MCPServerTools::handleNewTool(const json& input) {
// Extract input parameters
std::string param = input["param"];
// Call service
auto result = m_someService->doSomethingSync(param);
// Return JSON result
return {
{"output", result},
{"status", "success"}
};
}
```
3. **Register in getToolDefinitions()**:
```cpp
tools.push_back({
"new_tool",
"Description of what this tool does",
{
{"type", "object"},
{"properties", {
{"param", {
{"type", "string"},
{"description", "Parameter description"}
}}
}},
{"required", json::array({"param"})}
},
[this](const json& input) { return handleNewTool(input); }
});
```
4. **Add to execute() switch**:
```cpp
if (toolName == "new_tool") {
return handleNewTool(input);
}
```
### Testing MCP Server
Test with `nc` or `socat`:
```bash
# Send tools/list request
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | ./build/aissia.exe --mcp-server
# Send tool call
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"chat_with_aissia","arguments":{"message":"Hello AISSIA"}}}' | ./build/aissia.exe --mcp-server
```
Expected output format:
```json
{"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"chat_with_aissia","description":"...","inputSchema":{...}}]}}
```
## Troubleshooting
### "LLMService not initialized"
Make sure `config/ai.json` exists with valid API key:
```json
{
"provider": "claude",
"api_key": "sk-ant-...",
"model": "claude-sonnet-4-20250514"
}
```
### "VoiceService not available"
Voice tools are optional. If you don't need STT/TTS, this is normal.
### "StorageService not available"
Make sure `config/storage.json` exists:
```json
{
"database_path": "./data/aissia.db",
"journal_mode": "WAL",
"busy_timeout_ms": 5000
}
```
### "Tool not found"
Check `tools/list` output to see which tools are actually registered.
## References
- **MCP Specification**: https://github.com/anthropics/mcp
- **AISSIA Architecture**: `docs/project-overview.md`
- **GroveEngine Guide**: `docs/GROVEENGINE_GUIDE.md`
- **LLM Service**: `src/services/LLMService.hpp`
- **MCPServer**: `src/shared/mcp/MCPServer.hpp`

View File

@ -8,6 +8,7 @@
#include "services/VoiceService.hpp"
#include "shared/mcp/MCPServer.hpp"
#include "shared/tools/FileSystemTools.hpp"
#include "shared/tools/MCPServerTools.hpp"
#include "shared/llm/ToolRegistry.hpp"
#include <spdlog/spdlog.h>
@ -177,14 +178,32 @@ private:
// Run AISSIA as MCP server (stdio mode)
int runMCPServer() {
// Log to stderr so stdout stays clean for JSON-RPC
// Use stderr_color_sink from stdout_color_sinks.h
auto logger = spdlog::stderr_color_mt("MCPServer");
spdlog::set_default_logger(logger);
spdlog::set_level(spdlog::level::info);
spdlog::info("AISSIA MCP Server starting...");
// Create tool registry with FileSystem tools
// === Initialize Services ===
// 1. LLMService (PRIORITY: for chat_with_aissia)
auto llmService = std::make_unique<aissia::LLMService>();
if (!llmService->loadConfig("config/llm.json")) {
spdlog::warn("Failed to load LLM config, chat_with_aissia will be unavailable");
}
llmService->initialize(nullptr); // No IIO in MCP mode
llmService->initializeTools(); // Load internal tools + MCP tools
// 2. StorageService (for save_memory/search_memories)
auto storageService = std::make_unique<aissia::StorageService>();
storageService->initialize(nullptr);
// 3. VoiceService (for TTS/STT)
auto voiceService = std::make_unique<aissia::VoiceService>();
// Note: Voice config is optional
voiceService->initialize(nullptr);
// === Create Tool Registry ===
aissia::ToolRegistry registry;
// Register get_current_time tool
@ -214,7 +233,18 @@ int runMCPServer() {
);
}
spdlog::info("Registered {} tools", registry.size());
// === Register AISSIA Tools (Phase 8) ===
aissia::tools::MCPServerTools aissiaTools(
llmService.get(),
storageService.get(),
voiceService.get()
);
for (const auto& toolDef : aissiaTools.getToolDefinitions()) {
registry.registerTool(toolDef);
}
spdlog::info("Registered {} tools total", registry.size());
// Create and run MCP server
aissia::mcp::MCPServer server(registry);

View File

@ -340,4 +340,36 @@ void LLMService::shutdown() {
m_logger->info("LLMService shutdown");
}
LLMService::SyncResponse LLMService::sendMessageSync(
const std::string& message,
const std::string& conversationId,
const std::string& systemPrompt
) {
SyncResponse syncResp;
// Create request (same as async mode)
Request request;
request.query = message;
request.conversationId = conversationId.empty() ? "mcp-session" : conversationId;
request.systemPrompt = systemPrompt.empty() ? m_defaultSystemPrompt : systemPrompt;
request.maxIterations = m_maxIterations;
// Process synchronously (blocking call)
auto response = processRequest(request);
// Convert to SyncResponse
if (!response.isError) {
syncResp.text = response.text;
syncResp.tokens = response.tokens;
syncResp.iterations = response.iterations;
} else {
// On error, return error in text
syncResp.text = "Error: " + response.text;
syncResp.tokens = 0;
syncResp.iterations = 0;
}
return syncResp;
}
} // namespace aissia

View File

@ -60,6 +60,29 @@ public:
/// Load MCP server configurations
bool loadMCPConfig(const std::string& configPath);
/**
* @brief Synchronous response structure for MCP Server mode
*/
struct SyncResponse {
std::string text;
int tokens = 0;
int iterations = 0;
};
/**
* @brief Send message synchronously (blocking, for MCP Server mode)
*
* @param message User message
* @param conversationId Conversation ID (optional)
* @param systemPrompt Custom system prompt (optional)
* @return Sync response with text, tokens, iterations
*/
SyncResponse sendMessageSync(
const std::string& message,
const std::string& conversationId = "",
const std::string& systemPrompt = ""
);
private:
struct Request {
std::string query;

View File

@ -4,6 +4,7 @@
#include <memory>
#include <string>
#include <queue>
#include <fstream>
// Include VoiceService.hpp BEFORE spdlog to avoid logger macro conflicts
#include "VoiceService.hpp"
@ -225,4 +226,69 @@ void VoiceService::shutdown() {
m_logger->info("[VoiceService] Shutdown");
}
bool VoiceService::loadConfig(const std::string& configPath) {
try {
std::ifstream file(configPath);
if (!file.is_open()) {
m_logger->warn("[VoiceService] Config file not found: {}", configPath);
return false;
}
nlohmann::json config;
file >> config;
// Load TTS config
if (config.contains("tts")) {
const auto& ttsConfig = config["tts"];
m_ttsEnabled = ttsConfig.value("enabled", true);
m_ttsRate = ttsConfig.value("rate", 0);
m_ttsVolume = ttsConfig.value("volume", 80);
}
// Load STT config (Phase 7 format)
if (config.contains("stt")) {
configureSTT(config["stt"]);
}
m_logger->info("[VoiceService] Config loaded from {}", configPath);
return true;
} catch (const std::exception& e) {
m_logger->error("[VoiceService] Failed to load config: {}", e.what());
return false;
}
}
std::string VoiceService::transcribeFileSync(
const std::string& filePath,
const std::string& language
) {
m_logger->info("[VoiceService] transcribeFileSync: {}", filePath);
if (!m_sttService) {
throw std::runtime_error("STT service not initialized");
}
// Use STT service to transcribe file synchronously
// Note: This requires STT service to support file transcription
// For MVP, we'll throw not implemented
throw std::runtime_error("transcribeFileSync not yet implemented - STT service needs file transcription support");
}
bool VoiceService::textToSpeechSync(
const std::string& text,
const std::string& outputFile,
const std::string& voice
) {
m_logger->info("[VoiceService] textToSpeechSync: {} -> {}", text.substr(0, 50), outputFile);
if (!m_ttsEngine) {
throw std::runtime_error("TTS engine not initialized");
}
// For MVP, we don't support saving to file yet
// The TTS engine currently only speaks directly
throw std::runtime_error("textToSpeechSync file output not yet implemented - TTS engine needs file output support");
}
} // namespace aissia

View File

@ -55,6 +55,35 @@ public:
/// Configure STT with full config (Phase 7)
void configureSTT(const nlohmann::json& sttConfig);
/// Load configuration from JSON file
bool loadConfig(const std::string& configPath);
/**
* @brief Transcribe audio file synchronously (for MCP Server mode)
*
* @param filePath Path to audio file
* @param language Language code (e.g., "fr", "en")
* @return Transcribed text
*/
std::string transcribeFileSync(
const std::string& filePath,
const std::string& language = "fr"
);
/**
* @brief Convert text to speech synchronously (for MCP Server mode)
*
* @param text Text to synthesize
* @param outputFile Output audio file path
* @param voice Voice identifier (e.g., "fr-fr")
* @return true if successful
*/
bool textToSpeechSync(
const std::string& text,
const std::string& outputFile,
const std::string& voice = "fr-fr"
);
private:
// Configuration
bool m_ttsEnabled = true;

View File

@ -0,0 +1,310 @@
#include "MCPServerTools.hpp"
#include "../../services/LLMService.hpp"
#include "../../services/StorageService.hpp"
#include "../../services/VoiceService.hpp"
#include <spdlog/spdlog.h>
namespace aissia::tools {
MCPServerTools::MCPServerTools(
LLMService* llm,
StorageService* storage,
VoiceService* voice
) : m_llmService(llm),
m_storageService(storage),
m_voiceService(voice)
{
}
std::vector<ToolDefinition> MCPServerTools::getToolDefinitions() {
std::vector<ToolDefinition> tools;
// Tool 1: chat_with_aissia (PRIORITÉ)
if (m_llmService) {
tools.push_back({
"chat_with_aissia",
"Dialogue with AISSIA assistant (Claude Sonnet 4). Send a message and get an intelligent response with access to AISSIA's knowledge and capabilities.",
{
{"type", "object"},
{"properties", {
{"message", {
{"type", "string"},
{"description", "Message to send to AISSIA"}
}},
{"conversation_id", {
{"type", "string"},
{"description", "Conversation ID for continuity (optional)"}
}},
{"system_prompt", {
{"type", "string"},
{"description", "Custom system prompt (optional)"}
}}
}},
{"required", json::array({"message"})}
},
[this](const json& input) { return handleChatWithAissia(input); }
});
}
// Tool 2: transcribe_audio
if (m_voiceService) {
tools.push_back({
"transcribe_audio",
"Transcribe audio file to text using Speech-to-Text (Whisper.cpp, OpenAI Whisper API, or Google Speech). Supports WAV, MP3, and other common audio formats.",
{
{"type", "object"},
{"properties", {
{"file_path", {
{"type", "string"},
{"description", "Path to audio file"}
}},
{"language", {
{"type", "string"},
{"description", "Language code (e.g., 'fr', 'en'). Default: 'fr'"}
}}
}},
{"required", json::array({"file_path"})}
},
[this](const json& input) { return handleTranscribeAudio(input); }
});
// Tool 3: text_to_speech
tools.push_back({
"text_to_speech",
"Convert text to speech audio file using Text-to-Speech synthesis. Generates audio in WAV format.",
{
{"type", "object"},
{"properties", {
{"text", {
{"type", "string"},
{"description", "Text to synthesize"}
}},
{"output_file", {
{"type", "string"},
{"description", "Output audio file path (WAV)"}
}},
{"voice", {
{"type", "string"},
{"description", "Voice identifier (e.g., 'fr-fr', 'en-us'). Default: 'fr-fr'"}
}}
}},
{"required", json::array({"text", "output_file"})}
},
[this](const json& input) { return handleTextToSpeech(input); }
});
}
// Tool 4: save_memory
if (m_storageService) {
tools.push_back({
"save_memory",
"Save a note or memory to AISSIA's persistent storage. Memories can be tagged and searched later.",
{
{"type", "object"},
{"properties", {
{"title", {
{"type", "string"},
{"description", "Memory title"}
}},
{"content", {
{"type", "string"},
{"description", "Memory content"}
}},
{"tags", {
{"type", "array"},
{"items", {{"type", "string"}}},
{"description", "Tags for categorization (optional)"}
}}
}},
{"required", json::array({"title", "content"})}
},
[this](const json& input) { return handleSaveMemory(input); }
});
// Tool 5: search_memories
tools.push_back({
"search_memories",
"Search through saved memories and notes in AISSIA's storage. Returns matching memories with relevance scores.",
{
{"type", "object"},
{"properties", {
{"query", {
{"type", "string"},
{"description", "Search query"}
}},
{"limit", {
{"type", "integer"},
{"description", "Maximum results to return. Default: 10"}
}}
}},
{"required", json::array({"query"})}
},
[this](const json& input) { return handleSearchMemories(input); }
});
}
return tools;
}
json MCPServerTools::execute(const std::string& toolName, const json& input) {
if (toolName == "chat_with_aissia") {
return handleChatWithAissia(input);
} else if (toolName == "transcribe_audio") {
return handleTranscribeAudio(input);
} else if (toolName == "text_to_speech") {
return handleTextToSpeech(input);
} else if (toolName == "save_memory") {
return handleSaveMemory(input);
} else if (toolName == "search_memories") {
return handleSearchMemories(input);
}
return {
{"error", "Unknown tool: " + toolName}
};
}
// ============================================================================
// Tool Handlers
// ============================================================================
json MCPServerTools::handleChatWithAissia(const json& input) {
if (!m_llmService) {
return {{"error", "LLMService not available"}};
}
try {
std::string message = input["message"];
std::string conversationId = input.value("conversation_id", "");
std::string systemPrompt = input.value("system_prompt", "");
spdlog::info("[chat_with_aissia] Message: {}", message.substr(0, 100));
// Call synchronous LLM method
auto response = m_llmService->sendMessageSync(message, conversationId, systemPrompt);
return {
{"response", response.text},
{"conversation_id", conversationId},
{"tokens", response.tokens},
{"iterations", response.iterations}
};
} catch (const std::exception& e) {
spdlog::error("[chat_with_aissia] Error: {}", e.what());
return {{"error", e.what()}};
}
}
json MCPServerTools::handleTranscribeAudio(const json& input) {
if (!m_voiceService) {
return {{"error", "VoiceService not available"}};
}
try {
std::string filePath = input["file_path"];
std::string language = input.value("language", "fr");
spdlog::info("[transcribe_audio] File: {}, Language: {}", filePath, language);
// Call synchronous STT method
std::string text = m_voiceService->transcribeFileSync(filePath, language);
return {
{"text", text},
{"file", filePath},
{"language", language}
};
} catch (const std::exception& e) {
spdlog::error("[transcribe_audio] Error: {}", e.what());
return {{"error", e.what()}};
}
}
json MCPServerTools::handleTextToSpeech(const json& input) {
if (!m_voiceService) {
return {{"error", "VoiceService not available"}};
}
try {
std::string text = input["text"];
std::string outputFile = input["output_file"];
std::string voice = input.value("voice", "fr-fr");
spdlog::info("[text_to_speech] Text: {}, Output: {}", text.substr(0, 50), outputFile);
// Call synchronous TTS method
bool success = m_voiceService->textToSpeechSync(text, outputFile, voice);
if (success) {
return {
{"success", true},
{"file", outputFile},
{"voice", voice}
};
} else {
return {{"error", "TTS generation failed"}};
}
} catch (const std::exception& e) {
spdlog::error("[text_to_speech] Error: {}", e.what());
return {{"error", e.what()}};
}
}
json MCPServerTools::handleSaveMemory(const json& input) {
if (!m_storageService) {
return {{"error", "StorageService not available"}};
}
try {
std::string title = input["title"];
std::string content = input["content"];
std::vector<std::string> tags;
if (input.contains("tags") && input["tags"].is_array()) {
for (const auto& tag : input["tags"]) {
tags.push_back(tag.get<std::string>());
}
}
spdlog::info("[save_memory] Title: {}", title);
// TODO: Implement saveMemorySync in StorageService
// For now, return not implemented
return json({
{"error", "save_memory not yet implemented"},
{"note", "StorageService sync methods need to be added"},
{"title", title}
});
} catch (const std::exception& e) {
spdlog::error("[save_memory] Error: {}", e.what());
return {{"error", e.what()}};
}
}
json MCPServerTools::handleSearchMemories(const json& input) {
if (!m_storageService) {
return {{"error", "StorageService not available"}};
}
try {
std::string query = input["query"];
int limit = input.value("limit", 10);
spdlog::info("[search_memories] Query: {}, Limit: {}", query, limit);
// TODO: Implement searchMemoriesSync in StorageService
// For now, return not implemented
return json({
{"error", "search_memories not yet implemented"},
{"note", "StorageService sync methods need to be added"},
{"query", query},
{"limit", limit}
});
} catch (const std::exception& e) {
spdlog::error("[search_memories] Error: {}", e.what());
return {{"error", e.what()}};
}
}
} // namespace aissia::tools

View File

@ -0,0 +1,76 @@
#pragma once
#include "../llm/ToolRegistry.hpp"
#include <nlohmann/json.hpp>
#include <memory>
#include <vector>
// Forward declarations
namespace aissia {
class LLMService;
class StorageService;
class VoiceService;
}
namespace aissia::tools {
using json = nlohmann::json;
/**
* @brief MCP Server Tools - Bridge between MCP Server and AISSIA services
*
* Provides tool definitions for AISSIA modules exposed via MCP Server:
* - chat_with_aissia: Dialogue with AISSIA (Claude Sonnet 4)
* - transcribe_audio: Speech-to-text (Whisper.cpp/OpenAI/Google)
* - text_to_speech: Text-to-speech synthesis
* - save_memory: Save note/memory to storage
* - search_memories: Search stored memories
*
* Note: These tools run in synchronous mode (no IIO pub/sub, no main loop)
*/
class MCPServerTools {
public:
/**
* @brief Construct MCP server tools with service dependencies
*
* @param llm LLMService for chat_with_aissia (can be nullptr)
* @param storage StorageService for save/search memories (can be nullptr)
* @param voice VoiceService for TTS/STT (can be nullptr)
*/
MCPServerTools(
LLMService* llm,
StorageService* storage,
VoiceService* voice
);
/**
* @brief Get all tool definitions for registration
*
* @return Vector of ToolDefinition structs
*/
std::vector<ToolDefinition> getToolDefinitions();
/**
* @brief Execute a tool by name
*
* @param toolName Tool to execute
* @param input Tool arguments (JSON)
* @return Tool result (JSON)
*/
json execute(const std::string& toolName, const json& input);
private:
// Tool handlers
json handleChatWithAissia(const json& input);
json handleTranscribeAudio(const json& input);
json handleTextToSpeech(const json& input);
json handleSaveMemory(const json& input);
json handleSearchMemories(const json& input);
// Service references (nullable)
LLMService* m_llmService;
StorageService* m_storageService;
VoiceService* m_voiceService;
};
} // namespace aissia::tools