|
@@ -0,0 +1,552 @@
|
|
|
|
|
+# MCP Mode Implementation Design for Valaq
|
|
|
|
|
+
|
|
|
|
|
+## 1. Overview
|
|
|
|
|
+
|
|
|
|
|
+This document provides a comprehensive design for implementing MCP (Model Context Protocol) mode in valaq, enabling VAPI file exploration through the MCP protocol using STDIO communication. The design leverages the existing valaq architecture while adding MCP capabilities through the mcp-vala library.
|
|
|
|
|
+
|
|
|
|
|
+## 2. Architecture Overview
|
|
|
|
|
+
|
|
|
|
|
+### 2.1 High-Level Architecture
|
|
|
|
|
+
|
|
|
|
|
+```mermaid
|
|
|
|
|
+graph TD
|
|
|
|
|
+ A[valaq --mcp] --> B[ArgumentParser]
|
|
|
|
|
+ B --> C{MCP Mode?}
|
|
|
|
|
+ C -->|Yes| D[McpModeCommandHandler]
|
|
|
|
|
+ C -->|No| E[NormalCommandHandler]
|
|
|
|
|
+ D --> F[McpServer]
|
|
|
|
|
+ F --> G[Mc p.Core.Server]
|
|
|
|
|
+ G --> H[Resource Providers]
|
|
|
|
|
+ H --> I[VapiResourceProvider]
|
|
|
|
|
+ I --> J[JSON Output]
|
|
|
|
|
+ J --> K[STDIO Transport]
|
|
|
|
|
+ K --> L[MCP Client]
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2.2 Component Integration
|
|
|
|
|
+
|
|
|
|
|
+The MCP mode integrates with existing valaq components:
|
|
|
|
|
+
|
|
|
|
|
+1. **ArgumentParser**: Extended to recognize `--mcp` flag
|
|
|
|
|
+2. **McpModeCommandHandler**: New component for MCP-specific command handling
|
|
|
|
|
+3. **McpServer**: Wrapper around `Mcp.Core.Server` with valaq-specific logic
|
|
|
|
|
+4. **VapiResourceProvider**: Custom resource provider for VAPI files
|
|
|
|
|
+5. **Existing Components**: Reuses VapiParser, SymbolNavigator, and JsonFormatter
|
|
|
|
|
+
|
|
|
|
|
+## 3. URI Scheme and Resource Mapping
|
|
|
|
|
+
|
|
|
|
|
+### 3.1 URI Scheme Design
|
|
|
|
|
+
|
|
|
|
|
+The MCP mode will use the `vapi://` URI scheme with the following patterns:
|
|
|
|
|
+
|
|
|
|
|
+1. **Root VAPI Listing**: `vapi://{vapi}`
|
|
|
|
|
+ - Returns JSON formatted list of root symbols (namespaces)
|
|
|
|
|
+ - Example: `vapi://gtk+-3.0`
|
|
|
|
|
+
|
|
|
|
|
+2. **Symbol Navigation**: `vapi://{vapi}/{symbol-path}`
|
|
|
|
|
+ - Returns JSON formatted symbol children
|
|
|
|
|
+ - Uses dot-separated symbol paths
|
|
|
|
|
+ - Example: `vapi://gtk+-3.0/Gtk.Window.show`
|
|
|
|
|
+
|
|
|
|
|
+### 3.2 Resource Mapping Strategy
|
|
|
|
|
+
|
|
|
|
|
+| URI Pattern | Resource Type | Implementation |
|
|
|
|
|
+|-------------|-------------|--------------|
|
|
|
|
|
+| `vapi://{vapi}` | VAPI Root Symbols | List all root symbols from parsed VAPI |
|
|
|
|
|
+| `vapi://{vapi}/{symbol}` | Symbol Children | Navigate to symbol and return children |
|
|
|
|
|
+| `vapi://{vapi}/{symbol-path}` | Symbol Path | Navigate to nested symbol using dot notation |
|
|
|
|
|
+
|
|
|
|
|
+## 4. VAPI Resource Provider Class Structure
|
|
|
|
|
+
|
|
|
|
|
+### 4.1 VapiResourceProvider Class
|
|
|
|
|
+
|
|
|
|
|
+```vala
|
|
|
|
|
+public class VapiResourceProvider : Mcp.Resources.BaseProvider {
|
|
|
|
|
+ private VapiParser parser;
|
|
|
|
|
+ private SymbolNavigator navigator;
|
|
|
|
|
+ private JsonFormatter formatter;
|
|
|
|
|
+ private HashTable<string, Gee.ArrayList<Symbol>> vapi_cache;
|
|
|
|
|
+
|
|
|
|
|
+ public VapiResourceProvider () {
|
|
|
|
|
+ // Initialize base provider
|
|
|
|
|
+ base ();
|
|
|
|
|
+
|
|
|
|
|
+ // Initialize components
|
|
|
|
|
+ parser = new VapiParser ();
|
|
|
|
|
+ navigator = null;
|
|
|
|
|
+ formatter = new JsonFormatter ();
|
|
|
|
|
+ vapi_cache = new HashTable<string, Gee.ArrayList<Symbol>> ();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public override async Gee.ArrayList<Mcp.Resources.Types.Resource> list_resources (string? cursor) throws Error {
|
|
|
|
|
+ var resources = new Gee.ArrayList<Mcp.Resources.Types.Resource> ();
|
|
|
|
|
+
|
|
|
|
|
+ // Get list of available VAPI files
|
|
|
|
|
+ var vapi_files = get_available_vapi_files ();
|
|
|
|
|
+
|
|
|
|
|
+ foreach (string vapi_file in vapi_files) {
|
|
|
|
|
+ string vapi_name = get_vapi_basename (vapi_file);
|
|
|
|
|
+ string uri = @"vapi://$(vapi_name)";
|
|
|
|
|
+
|
|
|
|
|
+ var resource = new Mcp.Resources.Types.Resource ();
|
|
|
|
|
+ resource.uri = uri;
|
|
|
|
|
+ resource.name = vapi_name;
|
|
|
|
|
+ resource.mime_type = "application/json";
|
|
|
|
|
+ resource.description = @"VAPI file: $(vapi_name)";
|
|
|
|
|
+
|
|
|
|
|
+ resources.add (resource);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return resources;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public override async Gee.ArrayList<Mcp.Types.Common.ResourceContents> read_resource (string uri) throws Error {
|
|
|
|
|
+ // Parse URI to extract VAPI name and symbol path
|
|
|
|
|
+ string[] uri_parts = uri.split ("://");
|
|
|
|
|
+ if (uri_parts.length != 2 || uri_parts[0] != "vapi") {
|
|
|
|
|
+ throw new Mcp.Core.McpError.INVALID_PARAMS ("Invalid VAPI URI format");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ string[] path_parts = uri_parts[1].split ("/");
|
|
|
|
|
+ string vapi_name = path_parts[0];
|
|
|
|
|
+ string? symbol_path = path_parts.length > 1 ? string.joinv (".", path_parts[1:]) : null;
|
|
|
|
|
+
|
|
|
|
|
+ // Resolve VAPI file path
|
|
|
|
|
+ string vapi_path = resolve_vapi_file (vapi_name);
|
|
|
|
|
+ if (vapi_path == null) {
|
|
|
|
|
+ throw new Mcp.Core.McpError.RESOURCE_NOT_FOUND ("VAPI file not found: %s".printf (vapi_name));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Parse VAPI file (use cache if available)
|
|
|
|
|
+ if (!vapi_cache.contains (vapi_name)) {
|
|
|
|
|
+ if (!parser.parse_file (vapi_path)) {
|
|
|
|
|
+ throw new Mcp.Core.McpError.PARSE_ERROR ("Failed to parse VAPI file: %s".printf (vapi_name));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var root_symbols = parser.get_root_symbols ();
|
|
|
|
|
+ vapi_cache.insert (vapi_name, root_symbols);
|
|
|
|
|
+ navigator = new SymbolNavigator (root_symbols);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var root_symbols = vapi_cache.lookup (vapi_name);
|
|
|
|
|
+
|
|
|
|
|
+ Gee.ArrayList<Mcp.Types.Common.ResourceContents> contents = new Gee.ArrayList<Mcp.Types.Common.ResourceContents> ();
|
|
|
|
|
+
|
|
|
|
|
+ if (symbol_path == null) {
|
|
|
|
|
+ // Return root symbols as JSON
|
|
|
|
|
+ string json_data = formatter.format_symbol_list (root_symbols);
|
|
|
|
|
+ var content = new Mcp.Types.Common.TextContent (json_data);
|
|
|
|
|
+ contents.add (content);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Navigate to symbol and return children
|
|
|
|
|
+ string[] symbol_parts = symbol_path.split (".");
|
|
|
|
|
+ Symbol? target_symbol = navigator.navigate_to_path (symbol_parts);
|
|
|
|
|
+
|
|
|
|
|
+ if (target_symbol == null) {
|
|
|
|
|
+ throw new Mcp.Core.McpError.RESOURCE_NOT_FOUND ("Symbol not found: %s".printf (symbol_path));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var child_symbols = navigator.get_child_symbols (target_symbol);
|
|
|
|
|
+ string json_data = formatter.format_symbol_list (child_symbols);
|
|
|
|
|
+ var content = new Mcp.Types.Common.TextContent (json_data);
|
|
|
|
|
+ contents.add (content);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return contents;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private string[] get_available_vapi_files () {
|
|
|
|
|
+ // Reuse existing file discovery logic
|
|
|
|
|
+ var file_utils = new FileUtils ();
|
|
|
|
|
+ return file_utils.find_all_vapi_files ();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private string get_vapi_basename (string vapi_file) {
|
|
|
|
|
+ // Extract basename without extension
|
|
|
|
|
+ if (vapi_file.has_suffix (".vapi")) {
|
|
|
|
|
+ return vapi_file.substring (0, vapi_file.length - 5);
|
|
|
|
|
+ }
|
|
|
|
|
+ return vapi_file;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private string? resolve_vapi_file (string vapi_name) {
|
|
|
|
|
+ // Reuse existing VAPI resolution logic
|
|
|
|
|
+ var file_utils = new FileUtils ();
|
|
|
|
|
+ return file_utils.resolve_vapi_file (vapi_name);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 4.2 Resource Content Structure
|
|
|
|
|
+
|
|
|
|
|
+The resource content follows the existing valaq JSON output format:
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "result_type": "symbol_list",
|
|
|
|
|
+ "symbols": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "name": "Gtk",
|
|
|
|
|
+ "type": "namespace",
|
|
|
|
|
+ "access": "public",
|
|
|
|
|
+ "full_path": "Gtk",
|
|
|
|
|
+ "child_count": 15
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 5. MCP Server Integration
|
|
|
|
|
+
|
|
|
|
|
+### 5.1 McpModeCommandHandler Class
|
|
|
|
|
+
|
|
|
|
|
+```vala
|
|
|
|
|
+public class McpModeCommandHandler : Object {
|
|
|
|
|
+ private McpServer mcp_server;
|
|
|
|
|
+
|
|
|
|
|
+ public McpModeCommandHandler (McpServer mcp_server) {
|
|
|
|
|
+ this.mcp_server = mcp_server;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public int handle_mcp_command () {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // Start MCP server in STDIO mode
|
|
|
|
|
+ bool started = yield mcp_server.start ();
|
|
|
|
|
+
|
|
|
|
|
+ if (!started) {
|
|
|
|
|
+ stderr.printf ("Failed to start MCP server\n");
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Keep main loop running
|
|
|
|
|
+ var loop = new MainLoop ();
|
|
|
|
|
+ loop.run ();
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ } catch (Error e) {
|
|
|
|
|
+ stderr.printf ("MCP server error: %s\n", e.message);
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 5.2 McpServer Class
|
|
|
|
|
+
|
|
|
|
|
+```vala
|
|
|
|
|
+public class McpServer : Object {
|
|
|
|
|
+ private Mcp.Core.Server mcp_core_server;
|
|
|
|
|
+ private VapiResourceProvider vapi_provider;
|
|
|
|
|
+
|
|
|
|
|
+ public McpServer () {
|
|
|
|
|
+ // Create server info
|
|
|
|
|
+ var server_info = new Mcp.Types.Protocol.ServerInfo (
|
|
|
|
|
+ "valaq",
|
|
|
|
|
+ "1.0.0",
|
|
|
|
|
+ "Valaq VAPI File Query Tool - MCP Server"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // Create capabilities
|
|
|
|
|
+ var capabilities = new Mcp.Types.Protocol.ServerCapabilities ();
|
|
|
|
|
+ capabilities.resources = new Mcp.Types.Protocol.ResourcesCapabilities ();
|
|
|
|
|
+ capabilities.resources.subscribe = true;
|
|
|
|
|
+ capabilities.resources.list_changed = true;
|
|
|
|
|
+
|
|
|
|
|
+ // Create MCP server
|
|
|
|
|
+ mcp_core_server = new Mcp.Core.Server (server_info, capabilities);
|
|
|
|
|
+
|
|
|
|
|
+ // Create and register VAPI resource provider
|
|
|
|
|
+ vapi_provider = new VapiResourceProvider ();
|
|
|
|
|
+ mcp_core_server.resource_manager.register_provider ("vapi", vapi_provider);
|
|
|
|
|
+
|
|
|
|
|
+ // Connect server signals
|
|
|
|
|
+ mcp_core_server.initialized.connect (on_server_initialized);
|
|
|
|
|
+ mcp_core_server.shutdown.connect (on_server_shutdown);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public async bool start () throws Error {
|
|
|
|
|
+ return yield mcp_core_server.start ();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public async void stop () {
|
|
|
|
|
+ yield mcp_core_server.stop ();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void on_server_initialized () {
|
|
|
|
|
+ // Server is ready for MCP communication
|
|
|
|
|
+ print ("MCP server initialized and ready\n");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void on_server_shutdown () {
|
|
|
|
|
+ // Cleanup resources
|
|
|
|
|
+ vapi_provider.cleanup ();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 6. Command-Line Argument Extension
|
|
|
|
|
+
|
|
|
|
|
+### 6.1 ArgumentParser Modifications
|
|
|
|
|
+
|
|
|
|
|
+```vala
|
|
|
|
|
+// In ArgumentParser class, add new field
|
|
|
|
|
+private bool mcp_mode;
|
|
|
|
|
+
|
|
|
|
|
+// In parse_long_option method, add:
|
|
|
|
|
+} else if (arg == "--mcp") {
|
|
|
|
|
+ mcp_mode = true;
|
|
|
|
|
+} else if (arg == "--help") {
|
|
|
|
|
+ show_help = true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Add new methods:
|
|
|
|
|
+public bool is_mcp_mode () {
|
|
|
|
|
+ return mcp_mode;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+public void show_mcp_help_text () {
|
|
|
|
|
+ print ("Valaq MCP Server Mode\n");
|
|
|
|
|
+ print ("====================\n\n");
|
|
|
|
|
+ print ("USAGE:\n");
|
|
|
|
|
+ print (" valaq --mcp\n\n");
|
|
|
|
|
+ print ("DESCRIPTION:\n");
|
|
|
|
|
+ print (" Starts valaq as an MCP server using STDIO communication.\n");
|
|
|
|
|
+ print (" Provides access to VAPI files through MCP protocol with vapi:// URI scheme.\n\n");
|
|
|
|
|
+ print ("RESOURCE ACCESS:\n");
|
|
|
|
|
+ print (" vapi://{vapi_name} - List root symbols in VAPI file\n");
|
|
|
|
|
+ print (" vapi://{vapi_name}/{symbol} - Navigate to symbol and list children\n");
|
|
|
|
|
+ print (" vapi://{vapi_name}/{path.to.symbol} - Navigate to nested symbol\n\n");
|
|
|
|
|
+ print ("EXAMPLES:\n");
|
|
|
|
|
+ print (" valaq --mcp\n");
|
|
|
|
|
+ print (" # Server starts and listens for MCP requests\n\n");
|
|
|
|
|
+ print ("EXIT CODES:\n");
|
|
|
|
|
+ print (" 0 Success\n");
|
|
|
|
|
+ print (" 1 MCP server error\n");
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 6.2 CommandHandler Integration
|
|
|
|
|
+
|
|
|
|
|
+```vala
|
|
|
|
|
+// In CommandHandler class, modify handle_command method:
|
|
|
|
|
+public int handle_command (ArgumentParser args) {
|
|
|
|
|
+ if (args.is_mcp_mode ()) {
|
|
|
|
|
+ // Create and run MCP server
|
|
|
|
|
+ var mcp_handler = new McpModeCommandHandler (mcp_server);
|
|
|
|
|
+ return mcp_handler.handle_mcp_command ();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ... existing command handling logic
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 7. Build System Changes
|
|
|
|
|
+
|
|
|
|
|
+### 7.1 Meson.build Updates
|
|
|
|
|
+
|
|
|
|
|
+```meson
|
|
|
|
|
+# Add mcp-vala dependency
|
|
|
|
|
+mcp_dep = dependency('mcp-vala')
|
|
|
|
|
+
|
|
|
|
|
+# Add MCP mode source files
|
|
|
|
|
+sources += files(
|
|
|
|
|
+ 'src/mcp/mcp-server.vala',
|
|
|
|
|
+ 'src/mcp/mcp-command-handler.vala',
|
|
|
|
|
+ 'src/mcp/vapi-resource-provider.vala'
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+# Update vala_args for MCP
|
|
|
|
|
+vala_args += [
|
|
|
|
|
+ '--pkg', 'mcp-vala'
|
|
|
|
|
+]
|
|
|
|
|
+
|
|
|
|
|
+# Update executable dependencies
|
|
|
|
|
+executable('valaq',
|
|
|
|
|
+ sources,
|
|
|
|
|
+ dependencies: [glib_dep, gobject_dep, json_glib_dep, gee_dep, libvala_dep, mcp_dep, jsonrpc_dep],
|
|
|
|
|
+ vala_args: vala_args,
|
|
|
|
|
+ install: true,
|
|
|
|
|
+)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 7.2 New Directory Structure
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+src/
|
|
|
|
|
+├── mcp/
|
|
|
|
|
+│ ├── mcp-server.vala # Main MCP server implementation
|
|
|
|
|
+│ ├── mcp-command-handler.vala # MCP mode command handling
|
|
|
|
|
+│ └── vapi-resource-provider.vala # VAPI resource provider
|
|
|
|
|
+├── cli/
|
|
|
|
|
+│ ├── argument-parser.vala # Extended for --mcp flag
|
|
|
|
|
+│ └── command-handler.vala # Modified for MCP mode
|
|
|
|
|
+└── [existing files...]
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 8. Error Handling and Logging
|
|
|
|
|
+
|
|
|
|
|
+### 8.1 Error Handling Strategy
|
|
|
|
|
+
|
|
|
|
|
+1. **MCP Protocol Errors**: Use `Mcp.Core.McpError` domain with proper error codes
|
|
|
|
|
+2. **VAPI Parsing Errors**: Wrap existing `ValaqError` with MCP error responses
|
|
|
|
|
+3. **Resource Not Found**: Return proper MCP error codes for invalid URIs
|
|
|
|
|
+4. **STDIO Transport Errors**: Handle JSON-RPC communication failures
|
|
|
|
|
+
|
|
|
|
|
+### 8.2 Logging Strategy
|
|
|
|
|
+
|
|
|
|
|
+1. **MCP Server Logs**: Use `print()` for server status messages
|
|
|
|
|
+2. **Error Logging**: Use `stderr.printf()` for error messages
|
|
|
|
|
+3. **Debug Logging**: Optional verbose mode for troubleshooting
|
|
|
|
|
+4. **MCP Protocol Logging**: Leverage mcp-vala's built-in logging capabilities
|
|
|
|
|
+
|
|
|
|
|
+## 9. Implementation Roadmap
|
|
|
|
|
+
|
|
|
|
|
+### 9.1 Phase 1: Core MCP Infrastructure
|
|
|
|
|
+1. **Create MCP Server Classes**
|
|
|
|
|
+ - Implement `McpServer` wrapper class
|
|
|
|
|
+ - Implement `McpModeCommandHandler` for MCP mode
|
|
|
|
|
+ - Set up basic server initialization and lifecycle
|
|
|
|
|
+
|
|
|
|
|
+2. **Implement VAPI Resource Provider**
|
|
|
|
|
+ - Create `VapiResourceProvider` class
|
|
|
|
|
+ - Implement resource listing and reading
|
|
|
|
|
+ - Integrate with existing VAPI parsing logic
|
|
|
|
|
+
|
|
|
|
|
+3. **Extend Command-Line Interface**
|
|
|
|
|
+ - Add `--mcp` flag to `ArgumentParser`
|
|
|
|
|
+ - Update `CommandHandler` for MCP mode detection
|
|
|
|
|
+ - Add help text for MCP mode
|
|
|
|
|
+
|
|
|
|
|
+### 9.2 Phase 2: Integration and Testing
|
|
|
|
|
+1. **Integrate Components**
|
|
|
|
|
+ - Connect MCP server to resource provider
|
|
|
|
|
+ - Implement proper error handling
|
|
|
|
|
+ - Add resource caching for performance
|
|
|
|
|
+
|
|
|
|
|
+2. **Testing**
|
|
|
|
|
+ - Unit tests for VAPI resource provider
|
|
|
|
|
+ - Integration tests for MCP protocol
|
|
|
|
|
+ - Manual testing with MCP clients
|
|
|
|
|
+
|
|
|
|
|
+3. **Documentation**
|
|
|
|
|
+ - Update README with MCP mode instructions
|
|
|
|
|
+ - Add examples of MCP client usage
|
|
|
|
|
+ - Document URI scheme and resource access
|
|
|
|
|
+
|
|
|
|
|
+### 9.3 Phase 3: Optimization and Polish
|
|
|
|
|
+1. **Performance Optimization**
|
|
|
|
|
+ - Implement resource caching
|
|
|
|
|
+ - Optimize VAPI parsing for large files
|
|
|
|
|
+ - Add lazy loading for symbol details
|
|
|
|
|
+
|
|
|
|
|
+2. **Advanced Features**
|
|
|
|
|
+ - Resource change notifications
|
|
|
|
|
+ - Symbol search capabilities
|
|
|
|
|
+ - Custom resource templates
|
|
|
|
|
+
|
|
|
|
|
+## 10. Testing Strategy
|
|
|
|
|
+
|
|
|
|
|
+### 10.1 Unit Testing
|
|
|
|
|
+
|
|
|
|
|
+```vala
|
|
|
|
|
+// Test VAPI resource provider
|
|
|
|
|
+class VapiResourceProviderTest : TestCase {
|
|
|
|
|
+ private VapiResourceProvider provider;
|
|
|
|
|
+
|
|
|
|
|
+ protected override void set_up () {
|
|
|
|
|
+ provider = new VapiResourceProvider ();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void test_list_resources () {
|
|
|
|
|
+ var resources = provider.list_resources (null);
|
|
|
|
|
+ assert (resources.size > 0);
|
|
|
|
|
+
|
|
|
|
|
+ // Test specific VAPI URI
|
|
|
|
|
+ var contents = provider.read_resource ("vapi://gtk+-3.0");
|
|
|
|
|
+ assert (contents != null);
|
|
|
|
|
+ assert (contents.size > 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void test_read_resource_invalid_uri () {
|
|
|
|
|
+ try {
|
|
|
|
|
+ provider.read_resource ("invalid://format");
|
|
|
|
|
+ assert_not_reached ();
|
|
|
|
|
+ } catch (Mcp.Core.McpError e) {
|
|
|
|
|
+ assert (e.code == -32603); // INVALID_PARAMS
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 10.2 Integration Testing
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# Test MCP server with sample client
|
|
|
|
|
+./valaq --mcp &
|
|
|
|
|
+echo '{"jsonrpc": "2.0", "method": "resources/list", "id": "test1"}' | ./valaq --mcp
|
|
|
|
|
+
|
|
|
|
|
+# Expected response
|
|
|
|
|
+{
|
|
|
|
|
+ "result": {
|
|
|
|
|
+ "resources": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "uri": "vapi://gtk+-3.0",
|
|
|
|
|
+ "name": "gtk+-3.0",
|
|
|
|
|
+ "mime_type": "application/json",
|
|
|
|
|
+ "description": "VAPI file: gtk+-3.0"
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 10.3 Performance Testing
|
|
|
|
|
+
|
|
|
|
|
+1. **Large VAPI Files**: Test with complex VAPIs like GTK
|
|
|
|
|
+2. **Concurrent Access**: Test multiple simultaneous requests
|
|
|
|
|
+3. **Memory Usage**: Monitor memory consumption
|
|
|
|
|
+4. **Response Times**: Ensure timely responses
|
|
|
|
|
+
|
|
|
|
|
+## 11. Security Considerations
|
|
|
|
|
+
|
|
|
|
|
+### 11.1 Input Validation
|
|
|
|
|
+
|
|
|
|
|
+1. **URI Validation**: Validate `vapi://` URIs strictly
|
|
|
|
|
+2. **Path Traversal**: Prevent directory traversal attacks
|
|
|
|
|
+3. **VAPI Names**: Only allow known VAPI file names
|
|
|
|
|
+4. **Symbol Paths**: Validate symbol path components
|
|
|
|
|
+
|
|
|
|
|
+### 11.2 Resource Access Control
|
|
|
|
|
+
|
|
|
|
|
+1. **VAPI Directories**: Restrict to standard VAPI locations
|
|
|
|
|
+2. **File Permissions**: Ensure proper read access
|
|
|
|
|
+3. **Resource Limits**: Implement rate limiting if needed
|
|
|
|
|
+
|
|
|
|
|
+## 12. Migration and Compatibility
|
|
|
|
|
+
|
|
|
|
|
+### 12.1 Backward Compatibility
|
|
|
|
|
+
|
|
|
|
|
+1. **Existing CLI**: Maintain full compatibility with current CLI
|
|
|
|
|
+2. **JSON Format**: Use existing JSON output structure
|
|
|
|
|
+3. **VAPI Parsing**: Leverage existing libvala integration
|
|
|
|
|
+
|
|
|
|
|
+### 12.2 MCP Protocol Compliance
|
|
|
|
|
+
|
|
|
|
|
+1. **Standard MCP**: Follow MCP v2025-11-25 specification
|
|
|
|
|
+2. **JSON-RPC 2.0**: Use mcp-vala's implementation
|
|
|
|
|
+3. **Error Codes**: Use standard MCP error codes
|
|
|
|
|
+4. **Resource Types**: Implement standard resource content types
|
|
|
|
|
+
|
|
|
|
|
+## 13. Summary
|
|
|
|
|
+
|
|
|
|
|
+This design provides a comprehensive approach to implementing MCP mode in valaq that:
|
|
|
|
|
+
|
|
|
|
|
+1. **Leverages Existing Architecture**: Reuses proven VAPI parsing and navigation logic
|
|
|
|
|
+2. **Clean Integration**: Minimal changes to existing components
|
|
|
|
|
+3. **Standard MCP Compliance**: Uses mcp-vala library for protocol implementation
|
|
|
|
|
+4. **Flexible Resource Access**: Provides intuitive VAPI exploration through MCP protocol
|
|
|
|
|
+5. **Robust Error Handling**: Comprehensive error handling and logging
|
|
|
|
|
+6. **Performance Optimized**: Caching and efficient resource access
|
|
|
|
|
+7. **Thoroughly Tested**: Complete testing strategy for reliability
|
|
|
|
|
+
|
|
|
|
|
+The implementation follows valaq's modular design principles while adding MCP capabilities through well-defined interfaces and standard protocols.
|