clanker 1 ماه پیش
والد
کامیت
92b1147690

+ 81 - 64
README.md

@@ -75,8 +75,8 @@ int main (string[] args) {
     // Create and start server
     var server = new Mcp.Core.Server (server_info, capabilities);
     
-    // Run the server (blocking)
-    server.run.begin ();
+    // Start the server (blocking)
+    bool started = yield server.start ();
     
     // Keep the main loop running
     var loop = new MainLoop ();
@@ -115,38 +115,34 @@ server.resource_manager.register_provider (provider);
 Tools are functions that clients can execute, such as running commands, performing calculations, or interacting with external services.
 
 ```vala
-public class CalculatorTool : Object, Mcp.Tools.Executor {
-    public Mcp.Tools.Types.ToolDefinition get_definition () {
-        var input_schema = new Json.Object ();
-        input_schema.set_string_member ("type", "object");
+public class CalculatorTool : Mcp.Tools.BaseExecutor {
+    public CalculatorTool () {
+        // Define input schema using Variant
+        var input_schema = Mcp.Types.VariantUtils.new_dict_builder ();
+        input_schema.add ("{sv}", "type", new Variant.string ("object"));
         
-        var properties = new Json.Object ();
+        var properties = Mcp.Types.VariantUtils.new_dict_builder ();
         
-        var expr_prop = new Json.Object ();
-        expr_prop.set_string_member ("type", "string");
-        expr_prop.set_string_member ("description", "Mathematical expression to evaluate");
-        properties.set_object_member ("expression", expr_prop);
+        var expr_prop = Mcp.Types.VariantUtils.new_dict_builder ();
+        expr_prop.add ("{sv}", "type", new Variant.string ("string"));
+        expr_prop.add ("{sv}", "description", new Variant.string ("Mathematical expression to evaluate"));
+        properties.add ("{sv}", "expression", expr_prop.end ());
         
-        input_schema.set_object_member ("properties", properties);
-        input_schema.set_array_member ("required", new Json.Array ());
+        var required = new VariantBuilder (new VariantType ("as"));
+        required.add_value ("s", "expression");
+        input_schema.add ("{sv}", "properties", properties.end ());
+        input_schema.add ("{sv}", "required", required.end ());
         
-        return new Mcp.Tools.Types.ToolDefinition ("calculator", input_schema);
+        base (new Mcp.Tools.Types.ToolDefinition ("calculator", input_schema.end ()));
     }
     
-    public async Mcp.Tools.Types.CallToolResult execute (Json.Object arguments) throws Error {
-        string expression = arguments.get_string_member ("expression");
+    protected override async Mcp.Tools.Types.CallToolResult do_execute (Variant arguments) throws Error {
+        string expression = get_string_arg (arguments, "expression");
         
         // Simple evaluation (in production, use a proper math parser)
         string result = eval_expression (expression);
         
-        var content = new Mcp.Types.Common.TextContent (result);
-        var contents = new Gee.ArrayList<Mcp.Types.Common.ContentBlock> ();
-        contents.add (content);
-        
-        var call_result = new Mcp.Tools.Types.CallToolResult ();
-        call_result.content = contents;
-        
-        return call_result;
+        return create_text_result ("Result: %s".printf (result));
     }
 }
 
@@ -159,36 +155,36 @@ server.tool_manager.register_executor (new CalculatorTool ());
 Prompts are templates that can be filled with arguments to generate consistent messages for language models.
 
 ```vala
-public class CodeReviewPrompt : Object, Mcp.Prompts.Template {
-    public Mcp.Prompts.Types.PromptDefinition get_definition () {
-        var prompt = new Mcp.Prompts.Types.PromptDefinition ("code_review");
-        prompt.description = "Generate a code review for the provided code";
+public class CodeReviewPrompt : Mcp.Prompts.BaseTemplate {
+    public CodeReviewPrompt () {
+        var arguments = new Gee.ArrayList<Mcp.Prompts.Types.PromptArgument> ();
         
         var code_arg = new Mcp.Prompts.Types.PromptArgument ("code");
         code_arg.description = "The code to review";
         code_arg.required = true;
-        prompt.arguments.add (code_arg);
+        arguments.add (code_arg);
         
         var style_arg = new Mcp.Prompts.Types.PromptArgument ("style");
         style_arg.description = "Review style (strict, moderate, relaxed)";
-        prompt.arguments.add (style_arg);
+        arguments.add (style_arg);
         
-        return prompt;
+        base ("code_review", "Generate a code review for the provided code", arguments);
     }
     
-    public async Mcp.Prompts.Types.GetPromptResult render (Json.Object arguments) throws Error {
-        string code = arguments.get_string_member ("code");
-        string style = arguments.has_member ("style") ? arguments.get_string_member ("style") : "moderate";
+    protected override async Mcp.Prompts.Types.GetPromptResult do_render (Variant arguments) throws Error {
+        string code = Mcp.Types.VariantUtils.get_string (arguments, "code");
+        string style = Mcp.Types.VariantUtils.has_key (arguments, "style")
+            ? Mcp.Types.VariantUtils.get_string (arguments, "style")
+            : "moderate";
         
         string prompt_text = @"Please review the following code using a $style style:\n\n$code\n\nProvide feedback on:\n1. Code quality\n2. Potential bugs\n3. Performance considerations\n4. Best practices";
         
         var content = new Mcp.Types.Common.TextContent (prompt_text);
         var message = new Mcp.Prompts.Types.PromptMessage ("user", content);
+        var messages = new Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> ();
+        messages.add (message);
         
-        var result = new Mcp.Prompts.Types.GetPromptResult ();
-        result.messages.add (message);
-        
-        return result;
+        return new Mcp.Prompts.Types.GetPromptResult (messages);
     }
 }
 
@@ -202,6 +198,8 @@ server.prompt_manager.register_template (new CodeReviewPrompt ());
 
 - [`Mcp.Core.Server`](src/core/server.vala): Main server class that handles the MCP protocol using Jsonrpc.Server
 - [`Mcp.Core.Error`](src/core/error.vala): Error domain and utilities
+- [`Mcp.Core.InjectContentLength`](src/core/compat.vala): Utility for injecting Content-Length headers in messages
+- [`Mcp.Core.StripContentLength`](src/core/compat.vala): Utility for stripping Content-Length headers from messages
 
 ### Manager Classes
 
@@ -209,10 +207,23 @@ server.prompt_manager.register_template (new CodeReviewPrompt ());
 - [`Mcp.Tools.Manager`](src/tools/manager.vala): Manages tool executors and handles tool operations
 - [`Mcp.Prompts.Manager`](src/prompts/manager.vala): Manages prompt templates and handles prompt operations
 
+### Base Classes
+
+- [`Mcp.Resources.BaseProvider`](src/resources/provider.vala): Base implementation for resource providers
+- [`Mcp.Tools.BaseExecutor`](src/tools/executor.vala): Base implementation for tool executors
+- [`Mcp.Prompts.BaseTemplate`](src/prompts/template.vala): Base implementation for prompt templates
+
 ### Type Definitions
 
 - [`Mcp.Types.Protocol`](src/types/protocol.vala): Core protocol types (ServerInfo, Capabilities, etc.)
 - [`Mcp.Types.Common`](src/types/common.vala): Common content types used across the protocol
+- [`Mcp.Types.VariantUtils`](src/types/variant_utils.vala): Utility functions for working with GLib.Variant
+
+### Tool Execution Classes
+
+- [`Mcp.Tools.Types.ToolExecutionContext`](src/tools/types.vala): Context for tool execution with progress tracking
+- [`Mcp.Tools.Types.ToolProgress`](src/tools/types.vala): Progress information for long-running tools
+- [`Mcp.Tools.Types.ToolAnnotations`](src/tools/types.vala): Annotations for tool execution results
 
 ## Building and Testing
 
@@ -259,12 +270,14 @@ meson compile -C builddir examples
 var server_info = new Mcp.Types.Protocol.ServerInfo (
     "my-server",
     "1.0.0",
-    "Description of my MCP server"
+    "Description of my MCP server",
+    "https://my-server.example.com"  // Optional website URL
 );
 
 // Configure capabilities
 var capabilities = new Mcp.Types.Protocol.ServerCapabilities ();
 capabilities.logging = true;
+capabilities.completions = new Mcp.Types.Protocol.CompletionsCapabilities ();
 capabilities.resources = new Mcp.Types.Protocol.ResourcesCapabilities ();
 capabilities.tools = new Mcp.Types.Protocol.ToolsCapabilities ();
 capabilities.prompts = new Mcp.Types.Protocol.PromptsCapabilities ();
@@ -281,7 +294,7 @@ The library provides a comprehensive error domain with proper JSON-RPC error cod
 try {
     var result = yield server.tool_manager.call_tool ("calculator", arguments);
     // Handle result
-} catch (Mcp.Core.McpError e) {
+} catch (Mcp.Core.Error e) {
     // Handle MCP-specific errors
     stderr.printf ("MCP Error: %s (code: %d)\n", e.message, e.code);
 } catch (Error e) {
@@ -323,36 +336,40 @@ The implementation follows these key design principles:
 mcp-vala/
 ├── src/
 │   ├── core/
-│   │   ├── error.vala              # Error domain and utilities
-│   │   └── server.vala             # Main server class using Jsonrpc.Server
+│   │   ├── compat.vala            # Compatibility utilities (InjectContentLength, StripContentLength)
+│   │   ├── error.vala            # Error domain and utilities
+│   │   └── server.vala           # Main server class using Jsonrpc.Server
 │   ├── types/
-│   │   ├── protocol.vala           # Protocol types (ServerInfo, Capabilities)
-│   │   └── common.vala           # Common content types
+│   │   ├── common.vala           # Common content types
+│   │   ├── protocol.vala         # Protocol types (ServerInfo, Capabilities)
+│   │   └── variant_utils.vala    # Variant utility functions
 │   ├── resources/
-│   │   ├── types.vala            # Resource data types
-│   │   ├── provider.vala          # Resource provider interface
-│   │   └── manager.vala          # Resource manager
+│   │   ├── manager.vala          # Resource manager
+│   │   ├── provider.vala         # Resource provider interface and base class
+│   │   └── types.vala            # Resource data types
 │   ├── tools/
-│   │   ├── types.vala            # Tool data types
-│   │   ├── executor.vala          # Tool executor interface
-│   │   └── manager.vala          # Tool manager
+│   │   ├── executor.vala         # Tool executor interface and base class
+│   │   ├── manager.vala          # Tool manager
+│   │   └── types.vala            # Tool data types
 │   ├── prompts/
-│   │   ├── types.vala            # Prompt data types
-│   │   ├── template.vala          # Prompt template interface
-│   │   └── manager.vala          # Prompt manager
-│   └── meson.build                # Library build configuration
+│   │   ├── manager.vala          # Prompt manager
+│   │   ├── template.vala         # Prompt template interface and base class
+│   │   └── types.vala            # Prompt data types
+│   └── meson.build               # Library build configuration
 ├── examples/
-│   ├── minimal-server.vala        # Minimal server example
-│   ├── filesystem-server.vala     # File system resource example
-│   ├── calculator-server.vala     # Tool execution example
-│   ├── chat-server.vala           # Prompt handling example
-│   └── meson.build               # Examples build configuration
+│   ├── minimal-server.vala       # Minimal server example
+│   ├── simple-server.vala        # Simple server with resources
+│   ├── filesystem-server.vala    # File system resource example
+│   ├── calculator-server.vala    # Tool execution example
+│   ├── chat-server.vala          # Prompt handling example
+│   └── meson.build              # Examples build configuration
 ├── docs/
-│   ├── developer-guide.md        # Developer guide
-│   └── api-reference.md          # API documentation
-├── meson.build                    # Main build configuration
-├── CHANGELOG.md                   # Version history
-└── README.md                     # This file
+│   ├── api-reference.md         # API documentation
+│   ├── developer-guide.md       # Developer guide
+│   └── meson.build              # Documentation build configuration
+├── meson.build                  # Main build configuration
+├── .gitignore                   # Git ignore file
+└── README.md                    # This file
 ```
 
 ## License

+ 0 - 249
debug_prompt_serialization.py

@@ -1,249 +0,0 @@
-#!/usr/bin/env python3
-"""
-Debug script to test prompt serialization and identify the exact issue
-"""
-
-import subprocess
-import time
-import json
-import sys
-import os
-import threading
-import queue
-
-class MCPServerTester:
-    def __init__(self, server_path):
-        self.server_path = server_path
-        self.server_process = None
-        self.message_queue = queue.Queue()
-        
-    def start_server(self):
-        """Start MCP server process"""
-        print(f"Starting MCP server: {self.server_path}")
-        self.server_process = subprocess.Popen(
-            [self.server_path],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            text=False,
-            bufsize=0
-        )
-        
-        # Start thread to read stderr
-        stderr_thread = threading.Thread(target=self._read_stderr)
-        stderr_thread.daemon = True
-        stderr_thread.start()
-        
-        # Start thread to read stdout
-        stdout_thread = threading.Thread(target=self._read_stdout)
-        stdout_thread.daemon = True
-        stdout_thread.start()
-        
-        time.sleep(1)
-        
-    def _read_stderr(self):
-        """Read stderr output from server"""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                line = self.server_process.stderr.readline()
-                if line:
-                    print(f"SERVER STDERR: {line.decode().strip()}")
-            except:
-                break
-                
-    def _read_stdout(self):
-        """Read stdout output from server with Content-Length parsing"""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                # Read Content-Length header
-                line = self.server_process.stdout.readline()
-                if not line:
-                    break
-                    
-                line_str = line.decode().strip()
-                if line_str.startswith("Content-Length:"):
-                    content_length = int(line_str.split(":")[1].strip())
-                    
-                    # Read empty line
-                    self.server_process.stdout.readline()
-                    
-                    # Read JSON content
-                    json_data = self.server_process.stdout.read(content_length)
-                    if json_data:
-                        try:
-                            parsed = json.loads(json_data.decode())
-                            self.message_queue.put(parsed)
-                            print(f"SERVER MESSAGE: {json.dumps(parsed, indent=2)}")
-                        except json.JSONDecodeError as e:
-                            print(f"JSON DECODE ERROR: {e}")
-                            print(f"RAW DATA: {json_data}")
-            except:
-                break
-                        
-    def send_jsonrpc_request(self, method, params=None, id=1):
-        """Send a JSON-RPC request with Content-Length header"""
-        request = {
-            "jsonrpc": "2.0",
-            "method": method,
-            "id": id,
-            "params": params or {}
-        }
-            
-        request_str = json.dumps(request)
-        message = f"Content-Length: {len(request_str)}\r\n\r\n{request_str}"
-        print(f"SENDING: {repr(message)}")
-        
-        self.server_process.stdin.write(message.encode())
-        self.server_process.stdin.flush()
-        
-        try:
-            response = self.message_queue.get(timeout=10)
-            return response
-        except queue.Empty:
-            print("TIMEOUT: No response received")
-            return None
-            
-    def test_prompt_get(self):
-        """Test prompts/get to trigger the serialization issue"""
-        print("\n=== Testing Prompt Get ===")
-        
-        # Initialize first
-        init_params = {
-            "protocolVersion": "2025-11-25",
-            "capabilities": {},
-            "clientInfo": {
-                "name": "test-client",
-                "version": "1.0.0"
-            }
-        }
-        init_response = self.send_jsonrpc_request("initialize", init_params, id=0)
-        
-        if init_response and "result" in init_response:
-            print("✓ Server initialized successfully")
-        else:
-            print("✗ Failed to initialize server")
-            return False
-        
-        # List prompts first
-        print("\nListing prompts...")
-        list_response = self.send_jsonrpc_request("prompts/list", id=1)
-        
-        if list_response and "result" in list_response:
-            prompts = list_response["result"].get("prompts", [])
-            print(f"✓ Found {len(prompts)} prompts")
-            
-            if prompts:
-                # Try to get the first prompt
-                prompt_name = prompts[0]["name"]
-                print(f"\nGetting prompt: {prompt_name}")
-                
-                get_response = self.send_jsonrpc_request("prompts/get", {
-                    "name": prompt_name
-                }, id=2)
-                
-                if get_response:
-                    if "result" in get_response:
-                        print("✓ Prompt retrieved successfully")
-                        result = get_response["result"]
-                        
-                        # Check the structure of the response
-                        if "messages" in result:
-                            messages = result["messages"]
-                            print(f"✓ Found {len(messages)} messages")
-                            
-                            for i, message in enumerate(messages):
-                                print(f"\nMessage {i}:")
-                                print(f"  Role: {message.get('role')}")
-                                if "content" in message:
-                                    content = message["content"]
-                                    print(f"  Content type: {content.get('type')}")
-                                    print(f"  Content keys: {list(content.keys())}")
-                                    
-                                    # Check for specific issues
-                                    if content.get("type") in ["image", "audio"]:
-                                        if "mimeType" in content:
-                                            print(f"  ✓ Has mimeType: {content['mimeType']}")
-                                        else:
-                                            print("  ✗ Missing mimeType field")
-                                            if "mime_type" in content:
-                                                print(f"  ✗ Has mime_type instead of mimeType: {content['mime_type']}")
-                                        
-                                        if "data" in content:
-                                            print(f"  ✓ Has data field")
-                                        else:
-                                            print("  ✗ Missing data field")
-                                            
-                                    elif content.get("type") == "resource_link":
-                                        if "name" in content:
-                                            print(f"  ✓ Has name: {content['name']}")
-                                        else:
-                                            print("  ✗ Missing name field")
-                                            
-                                        if "uri" in content:
-                                            print(f"  ✓ Has uri: {content['uri']}")
-                                        else:
-                                            print("  ✗ Missing uri field")
-                                            
-                                    elif content.get("type") == "resource":
-                                        if "resource" in content:
-                                            print(f"  ✓ Has resource field")
-                                            resource = content["resource"]
-                                            print(f"    Resource keys: {list(resource.keys())}")
-                                        else:
-                                            print("  ✗ Missing resource field")
-                        else:
-                            print("✗ No messages field in response")
-                    else:
-                        print("✗ No result field in response")
-                        if "error" in get_response:
-                            error = get_response["error"]
-                            print(f"ERROR: {json.dumps(error, indent=2)}")
-                else:
-                    print("✗ Failed to get prompt")
-            else:
-                print("✗ No prompts found")
-        else:
-            print("✗ Failed to list prompts")
-            return False
-            
-    def stop_server(self):
-        """Stop MCP server process"""
-        if self.server_process:
-            print("\nStopping server...")
-            self.server_process.terminate()
-            try:
-                self.server_process.wait(timeout=5)
-            except subprocess.TimeoutExpired:
-                self.server_process.kill()
-            self.server_process = None
-
-def main():
-    if len(sys.argv) != 2:
-        print("Usage: python3 debug_prompt_serialization.py <server-executable>")
-        sys.exit(1)
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        sys.exit(1)
-        
-    tester = MCPServerTester(server_path)
-    
-    try:
-        tester.start_server()
-        time.sleep(2)
-        
-        # Test prompt get
-        tester.test_prompt_get()
-            
-    except KeyboardInterrupt:
-        print("\nTest interrupted by user")
-    except Exception as e:
-        print(f"\nError during test: {e}")
-        import traceback
-        traceback.print_exc()
-    finally:
-        tester.stop_server()
-
-if __name__ == "__main__":
-    main()

+ 0 - 202
debug_resources.py

@@ -1,202 +0,0 @@
-#!/usr/bin/env python3
-"""
-Debug resource handling to see actual response format
-"""
-
-import subprocess
-import time
-import json
-import sys
-import os
-import threading
-import queue
-import tempfile
-import shutil
-
-class MCPServerTester:
-    def __init__(self, server_path):
-        self.server_path = server_path
-        self.server_process = None
-        self.message_queue = queue.Queue()
-        self.test_dir = None
-        
-    def start_server(self):
-        """Start MCP server process"""
-        # Create a temporary directory for testing
-        self.test_dir = tempfile.mkdtemp(prefix="mcp_test_")
-        
-        # Create some test files
-        with open(os.path.join(self.test_dir, "test.txt"), "w") as f:
-            f.write("Hello, World!")
-            
-        print(f"Starting MCP server: {self.server_path} with test directory: {self.test_dir}")
-        self.server_process = subprocess.Popen(
-            [self.server_path, self.test_dir],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            text=False,
-            bufsize=0
-        )
-        
-        # Start thread to read stderr
-        stderr_thread = threading.Thread(target=self._read_stderr)
-        stderr_thread.daemon = True
-        stderr_thread.start()
-        
-        # Start thread to read stdout
-        stdout_thread = threading.Thread(target=self._read_stdout)
-        stdout_thread.daemon = True
-        stdout_thread.start()
-        
-        time.sleep(1)
-        
-    def _read_stderr(self):
-        """Read stderr output from server"""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                line = self.server_process.stderr.readline()
-                if line:
-                    print(f"SERVER STDERR: {line.decode().strip()}")
-            except:
-                break
-                
-    def _read_stdout(self):
-        """Read stdout output from server with Content-Length parsing"""
-        buffer = b""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                data = self.server_process.stdout.read(1)
-                if not data:
-                    break
-                buffer += data
-                
-                if b'\r\n\r\n' in buffer:
-                    headers, body = buffer.split(b'\r\n\r\n', 1)
-                    content_length = None
-                    
-                    for line in headers.split(b'\r\n'):
-                        if line.lower().startswith(b'content-length:'):
-                            content_length = int(line.split(b':')[1].strip())
-                            break
-                    
-                    if content_length is not None and len(body) >= content_length:
-                        message = body[:content_length]
-                        buffer = body[content_length:]
-                        
-                        try:
-                            parsed = json.loads(message.decode())
-                            self.message_queue.put(parsed)
-                        except json.JSONDecodeError as e:
-                            print(f"JSON DECODE ERROR: {e}")
-                            print(f"RAW MESSAGE: {message}")
-            except:
-                break
-                        
-    def send_jsonrpc_request(self, method, params=None, id=1):
-        """Send a JSON-RPC request with proper Content-Length header"""
-        request = {
-            "jsonrpc": "2.0",
-            "method": method,
-            "id": id,
-            "params": params or {}
-        }
-            
-        request_str = json.dumps(request)
-        message = f"Content-Length: {len(request_str)}\r\n\r\n{request_str}"
-        
-        self.server_process.stdin.write(message.encode())
-        self.server_process.stdin.flush()
-        
-        try:
-            response = self.message_queue.get(timeout=10)
-            return response
-        except queue.Empty:
-            print("TIMEOUT: No response received")
-            return None
-            
-    def cleanup(self):
-        """Clean up test environment"""
-        if self.test_dir and os.path.exists(self.test_dir):
-            shutil.rmtree(self.test_dir)
-            
-    def stop_server(self):
-        """Stop MCP server process"""
-        if self.server_process:
-            print("\nStopping server...")
-            self.server_process.terminate()
-            try:
-                self.server_process.wait(timeout=5)
-            except subprocess.TimeoutExpired:
-                self.server_process.kill()
-            self.server_process = None
-
-def main():
-    if len(sys.argv) != 2:
-        print("Usage: python3 debug_resources.py <server-executable>")
-        sys.exit(1)
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        sys.exit(1)
-        
-    tester = MCPServerTester(server_path)
-    
-    try:
-        tester.start_server()
-        time.sleep(2)
-        
-        # Initialize first
-        init_params = {
-            "protocolVersion": "2025-11-25",
-            "capabilities": {},
-            "clientInfo": {
-                "name": "test-client",
-                "version": "1.0.0"
-            }
-        }
-        init_response = tester.send_jsonrpc_request("initialize", init_params, id=0)
-        
-        if init_response:
-            print("✓ Server initialized successfully")
-            
-            # List resources
-            list_response = tester.send_jsonrpc_request("resources/list", id=1)
-            if list_response:
-                print(f"Resources list response: {json.dumps(list_response, indent=2)}")
-                
-                # Get first resource URI
-                if "result" in list_response and "resources" in list_response["result"]:
-                    resources = list_response["result"]["resources"]
-                    if resources:
-                        first_uri = resources[0]["uri"]
-                        print(f"Trying to read resource: {first_uri}")
-                        
-                        # Read resource
-                        read_response = tester.send_jsonrpc_request("resources/read", {"uri": first_uri}, id=2)
-                        if read_response:
-                            print(f"Resource read response: {json.dumps(read_response, indent=2)}")
-                        else:
-                            print("Failed to read resource")
-                    else:
-                        print("No resources found")
-                else:
-                    print("No resources in response")
-            else:
-                print("Failed to list resources")
-        else:
-            print("Failed to initialize server")
-            
-    except KeyboardInterrupt:
-        print("\nTest interrupted by user")
-    except Exception as e:
-        print(f"\nError during test: {e}")
-        import traceback
-        traceback.print_exc()
-    finally:
-        tester.stop_server()
-        tester.cleanup()
-
-if __name__ == "__main__":
-    main()

+ 0 - 202
debug_templates.py

@@ -1,202 +0,0 @@
-#!/usr/bin/env python3
-"""
-Debug script to check if templates are being handled properly
-"""
-
-import subprocess
-import time
-import json
-import sys
-import os
-import threading
-import queue
-import tempfile
-import shutil
-
-class MCPServerTester:
-    def __init__(self, server_path):
-        self.server_path = server_path
-        self.server_process = None
-        self.message_queue = queue.Queue()
-        self.test_dir = None
-        
-    def start_server(self):
-        """Start MCP server process"""
-        # Create a temporary directory for testing
-        self.test_dir = tempfile.mkdtemp(prefix="mcp_test_")
-        
-        # Create some test files
-        with open(os.path.join(self.test_dir, "test.txt"), "w") as f:
-            f.write("Hello, World!")
-            
-        print(f"Starting MCP server: {self.server_path} with test directory: {self.test_dir}")
-        self.server_process = subprocess.Popen(
-            [self.server_path, self.test_dir],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            text=False,
-            bufsize=0
-        )
-        
-        # Start thread to read stderr
-        stderr_thread = threading.Thread(target=self._read_stderr)
-        stderr_thread.daemon = True
-        stderr_thread.start()
-        
-        # Start thread to read stdout
-        stdout_thread = threading.Thread(target=self._read_stdout)
-        stdout_thread.daemon = True
-        stdout_thread.start()
-        
-        time.sleep(1)
-        
-    def _read_stderr(self):
-        """Read stderr output from server"""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                line = self.server_process.stderr.readline()
-                if line:
-                    print(f"SERVER STDERR: {line.decode().strip()}")
-            except:
-                break
-                
-    def _read_stdout(self):
-        """Read stdout output from server without Content-Length parsing"""
-        buffer = b""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                data = self.server_process.stdout.readline()
-                if not data:
-                    break
-                buffer += data
-                
-                # Try to parse JSON directly from each line
-                try:
-                    message = buffer.strip()
-                    if message:
-                        parsed = json.loads(message.decode())
-                        self.message_queue.put(parsed)
-                        print(f"SERVER MESSAGE: {json.dumps(parsed, indent=2)}")
-                        buffer = b""
-                except json.JSONDecodeError:
-                    # If not valid JSON yet, continue reading
-                    continue
-            except:
-                break
-                        
-    def send_jsonrpc_request(self, method, params=None, id=1):
-        """Send a JSON-RPC request without Content-Length header"""
-        request = {
-            "jsonrpc": "2.0",
-            "method": method,
-            "id": id,
-            "params": params or {}
-        }
-            
-        request_str = json.dumps(request)
-        message = f"{request_str}\n"
-        print(f"SENDING: {repr(message)}")
-        
-        self.server_process.stdin.write(message.encode())
-        self.server_process.stdin.flush()
-        
-        try:
-            response = self.message_queue.get(timeout=10)
-            return response
-        except queue.Empty:
-            print("TIMEOUT: No response received")
-            return None
-            
-    def test_templates(self):
-        """Test resource template functionality"""
-        print("\n=== Testing Resource Templates ===")
-        
-        # Initialize first
-        init_params = {
-            "protocolVersion": "2025-11-25",
-            "capabilities": {},
-            "clientInfo": {
-                "name": "test-client",
-                "version": "1.0.0"
-            }
-        }
-        init_response = self.send_jsonrpc_request("initialize", init_params, id=0)
-        
-        if init_response:
-            print("✓ Server initialized successfully")
-            print(f"Init response: {json.dumps(init_response, indent=2)}")
-        else:
-            print("✗ Failed to initialize server")
-            return False
-        
-        # Test templates/list
-        print("\nTesting resources/templates/list...")
-        templates_response = self.send_jsonrpc_request("resources/templates/list", id=7)
-        
-        if templates_response:
-            print(f"Templates response: {json.dumps(templates_response, indent=2)}")
-            
-            if "result" in templates_response:
-                result = templates_response["result"]
-                if "templates" in result:
-                    templates = result["templates"]
-                    print(f"✓ Found {len(templates)} templates")
-                    return True
-                else:
-                    print("✗ No templates field in response")
-                    return False
-            else:
-                print("✗ No result field in response")
-                return False
-        else:
-            print("✗ Failed to list templates")
-            return False
-            
-    def cleanup(self):
-        """Clean up test environment"""
-        if self.test_dir and os.path.exists(self.test_dir):
-            shutil.rmtree(self.test_dir)
-            
-    def stop_server(self):
-        """Stop MCP server process"""
-        if self.server_process:
-            print("\nStopping server...")
-            self.server_process.terminate()
-            try:
-                self.server_process.wait(timeout=5)
-            except subprocess.TimeoutExpired:
-                self.server_process.kill()
-            self.server_process = None
-
-def main():
-    if len(sys.argv) != 2:
-        print("Usage: python3 debug_templates.py <server-executable>")
-        sys.exit(1)
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        sys.exit(1)
-        
-    tester = MCPServerTester(server_path)
-    
-    try:
-        tester.start_server()
-        time.sleep(2)
-        
-        # Test templates
-        tester.test_templates()
-            
-    except KeyboardInterrupt:
-        print("\nTest interrupted by user")
-    except Exception as e:
-        print(f"\nError during test: {e}")
-        import traceback
-        traceback.print_exc()
-    finally:
-        tester.stop_server()
-        tester.cleanup()
-
-if __name__ == "__main__":
-    main()

+ 0 - 265
diagnose_serialization.py

@@ -1,265 +0,0 @@
-#!/usr/bin/env python3
-"""
-Diagnostic script to test content serialization and identify the exact issue
-"""
-
-import subprocess
-import json
-import sys
-import os
-import tempfile
-
-def test_content_serialization():
-    """Test content serialization by creating a simple test case"""
-    
-    # Create a test JSON that matches what the server should send
-    test_prompt_response = {
-        "jsonrpc": "2.0",
-        "id": 2,
-        "result": {
-            "description": "Test prompt",
-            "messages": [
-                {
-                    "role": "user",
-                    "content": {
-                        "type": "text",
-                        "text": "Hello, world!"
-                    }
-                },
-                {
-                    "role": "assistant", 
-                    "content": {
-                        "type": "image",
-                        "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==",
-                        "mimeType": "image/png"
-                    }
-                },
-                {
-                    "role": "user",
-                    "content": {
-                        "type": "resource",
-                        "resource": {
-                            "uri": "file:///example.txt",
-                            "text": "This is a test resource"
-                        }
-                    }
-                }
-            ]
-        }
-    }
-    
-    print("Testing JSON structure that should be valid:")
-    print(json.dumps(test_prompt_response, indent=2))
-    
-    # Try to validate this against a simple schema
-    try:
-        # Basic validation of the structure
-        result = test_prompt_response["result"]
-        messages = result["messages"]
-        
-        for i, message in enumerate(messages):
-            content = message["content"]
-            content_type = content["type"]
-            
-            print(f"\nMessage {i} - Type: {content_type}")
-            
-            if content_type == "text":
-                if "text" not in content:
-                    print(f"  ✗ Missing 'text' field")
-                else:
-                    print(f"  ✓ Has 'text' field")
-                    
-            elif content_type in ["image", "audio"]:
-                if "data" not in content:
-                    print(f"  ✗ Missing 'data' field")
-                else:
-                    print(f"  ✓ Has 'data' field")
-                    
-                if "mimeType" not in content:
-                    print(f"  ✗ Missing 'mimeType' field")
-                else:
-                    print(f"  ✓ Has 'mimeType' field: {content['mimeType']}")
-                    
-            elif content_type == "resource":
-                if "resource" not in content:
-                    print(f"  ✗ Missing 'resource' field")
-                else:
-                    resource = content["resource"]
-                    print(f"  ✓ Has 'resource' field with keys: {list(resource.keys())}")
-                    
-                    if "uri" not in resource:
-                        print(f"    ✗ Missing 'uri' in resource")
-                    else:
-                        print(f"    ✓ Has 'uri': {resource['uri']}")
-                        
-                    # Check if resource has either text or blob
-                    has_text = "text" in resource
-                    has_blob = "blob" in resource
-                    
-                    if not (has_text or has_blob):
-                        print(f"    ✗ Resource must have either 'text' or 'blob'")
-                    elif has_text:
-                        print(f"    ✓ Has 'text' content")
-                    elif has_blob:
-                        print(f"    ✓ Has 'blob' content")
-                        
-            elif content_type == "resource_link":
-                required_fields = ["name", "uri"]
-                for field in required_fields:
-                    if field not in content:
-                        print(f"  ✗ Missing '{field}' field")
-                    else:
-                        print(f"  ✓ Has '{field}': {content[field]}")
-                        
-        print("\n✓ Basic structure validation passed")
-        return True
-        
-    except Exception as e:
-        print(f"\n✗ Validation failed: {e}")
-        import traceback
-        traceback.print_exc()
-        return False
-
-def test_server_response():
-    """Test actual server response if available"""
-    if len(sys.argv) != 2:
-        print("Usage: python3 diagnose_serialization.py <server-executable>")
-        return False
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        return False
-    
-    print(f"\n{'='*60}")
-    print(f"Testing server: {server_path}")
-    print(f"{'='*60}")
-    
-    # Test the expected structure first
-    if not test_content_serialization():
-        print("✗ Basic structure validation failed")
-        return False
-    
-    # Try to test the actual server
-    try:
-        # Create a simple test script
-        test_script = '''
-import json
-import sys
-import subprocess
-
-# Start the server
-proc = subprocess.Popen([sys.argv[1]], 
-                      stdin=subprocess.PIPE, 
-                      stdout=subprocess.PIPE, 
-                      stderr=subprocess.PIPE,
-                      text=False)
-
-# Send initialize
-init_msg = {
-    "jsonrpc": "2.0",
-    "method": "initialize", 
-    "id": 0,
-    "params": {
-        "protocolVersion": "2025-11-25",
-        "capabilities": {},
-        "clientInfo": {"name": "test", "version": "1.0.0"}
-    }
-}
-
-msg_str = json.dumps(init_msg)
-proc.stdin.write(f"Content-Length: {len(msg_str)}\\r\\n\\r\\n{msg_str}".encode())
-proc.stdin.flush()
-
-# Read init response
-line = proc.stdout.readline()
-if line.startswith(b"Content-Length:"):
-    length = int(line.decode().split(":")[1].strip())
-    proc.stdout.readline()  # empty line
-    data = proc.stdout.read(length)
-    response = json.loads(data.decode())
-    print("Init response:", "success" if "result" in response else "failed")
-
-# List prompts
-list_msg = {"jsonrpc": "2.0", "method": "prompts/list", "id": 1, "params": {}}
-msg_str = json.dumps(list_msg)
-proc.stdin.write(f"Content-Length: {len(msg_str)}\\r\\n\\r\\n{msg_str}".encode())
-proc.stdin.flush()
-
-# Read list response
-line = proc.stdout.readline()
-if line.startswith(b"Content-Length:"):
-    length = int(line.decode().split(":")[1].strip())
-    proc.stdout.readline()  # empty line
-    data = proc.stdout.read(length)
-    response = json.loads(data.decode())
-    
-    if "result" in response and "prompts" in response["result"]:
-        prompts = response["result"]["prompts"]
-        print(f"Found {len(prompts)} prompts")
-        
-        if prompts:
-            # Get first prompt
-            get_msg = {"jsonrpc": "2.0", "method": "prompts/get", "id": 2, 
-                      "params": {"name": prompts[0]["name"]}}
-            msg_str = json.dumps(get_msg)
-            proc.stdin.write(f"Content-Length: {len(msg_str)}\\r\\n\\r\\n{msg_str}".encode())
-            proc.stdin.flush()
-            
-            # Read get response
-            line = proc.stdout.readline()
-            if line.startswith(b"Content-Length:"):
-                length = int(line.decode().split(":")[1].strip())
-                proc.stdout.readline()  # empty line
-                data = proc.stdout.read(length)
-                response = json.loads(data.decode())
-                
-                if "result" in response:
-                    print("✓ Got prompt result")
-                    result = response["result"]
-                    print(json.dumps(result, indent=2))
-                elif "error" in response:
-                    print("✗ Got error:")
-                    print(json.dumps(response["error"], indent=2))
-                else:
-                    print("✗ No result or error in response")
-
-proc.terminate()
-'''
-        
-        # Write test script to temp file
-        with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
-            f.write(test_script)
-            temp_script = f.name
-        
-        # Run the test
-        result = subprocess.run([sys.executable, temp_script, server_path], 
-                              capture_output=True, text=True, timeout=10)
-        
-        print("Server test output:")
-        print(result.stdout)
-        if result.stderr:
-            print("Server test errors:")
-            print(result.stderr)
-            
-        # Clean up
-        os.unlink(temp_script)
-        
-        return result.returncode == 0
-        
-    except subprocess.TimeoutExpired:
-        print("✗ Server test timed out")
-        return False
-    except Exception as e:
-        print(f"✗ Server test failed: {e}")
-        import traceback
-        traceback.print_exc()
-        return False
-
-if __name__ == "__main__":
-    if len(sys.argv) == 2:
-        success = test_server_response()
-    else:
-        success = test_content_serialization()
-    
-    sys.exit(0 if success else 1)

+ 237 - 67
docs/api-reference.md

@@ -90,7 +90,7 @@ The library now uses Jsonrpc.Server from jsonrpc-glib-1.0 for handling JSON-RPC
 - Proper STDIO transport handling
 - Automatic message parsing and formatting
 
-### Mcp.Core.McpError
+### Mcp.Core.Error
 
 Error domain for MCP-specific errors.
 
@@ -102,12 +102,48 @@ public static const int INVALID_REQUEST = -32600;
 public static const int METHOD_NOT_FOUND = -32601;
 public static const int INVALID_PARAMS = -32602;
 public static const int INTERNAL_ERROR = -32603;
-public static const int RESOURCE_NOT_FOUND = -32604;
-public static const int TRANSPORT_ERROR = -32605;
+public static const int NOT_FOUND = -32604;
+public static const int INVALID_ARGUMENT = -32605;
+```
+
+#### Convenience Constructors
+
+```vala
+public static Error PARSE (string message)
+public static Error INVALID_REQUEST (string message)
+public static Error METHOD_NOT_FOUND (string message)
+public static Error INVALID_PARAMS (string message)
+public static Error INTERNAL_ERROR (string message)
+public static Error NOT_FOUND (string message)
+public static Error INVALID_ARGUMENT (string message)
 ```
 
 ## Types Namespace
 
+### Mcp.Core.InjectContentLength
+
+Utility class for injecting Content-Length headers into messages.
+
+#### Methods
+
+```vala
+public static string process (string message)
+```
+
+Injects the Content-Length header into a JSON-RPC message.
+
+### Mcp.Core.StripContentLength
+
+Utility class for stripping Content-Length headers from messages.
+
+#### Methods
+
+```vala
+public static string process (string message)
+```
+
+Removes the Content-Length header from a JSON-RPC message.
+
 ### Mcp.Types.Protocol.ServerInfo
 
 Information about the MCP server.
@@ -118,7 +154,8 @@ Information about the MCP server.
 public ServerInfo (
     string name,
     string version,
-    string? description = null
+    string? description = null,
+    string? website_url = null
 )
 ```
 
@@ -128,6 +165,7 @@ public ServerInfo (
 public string name { get; set; }
 public string version { get; set; }
 public string? description { get; set; }
+public string? website_url { get; set; }
 ```
 
 ### Mcp.Types.Protocol.ServerCapabilities
@@ -138,11 +176,22 @@ Server capabilities configuration.
 
 ```vala
 public bool logging { get; set; }
+public Mcp.Types.Protocol.CompletionsCapabilities? completions { get; set; }
 public Mcp.Types.Protocol.ResourcesCapabilities? resources { get; set; }
 public Mcp.Types.Protocol.ToolsCapabilities? tools { get; set; }
 public Mcp.Types.Protocol.PromptsCapabilities? prompts { get; set; }
 ```
 
+### Mcp.Types.Protocol.CompletionsCapabilities
+
+Completion-related capabilities.
+
+#### Properties
+
+```vala
+public bool list_changed { get; set; }
+```
+
 ### Mcp.Types.Protocol.ResourcesCapabilities
 
 Resource-related capabilities.
@@ -296,6 +345,62 @@ public string? audience { get; set; }
 public bool? expire_time { get; set; }
 ```
 
+### Mcp.Types.VariantUtils
+
+Utility functions for working with GLib.Variant data structures.
+
+#### Dictionary Builder Methods
+
+```vala
+public static VariantBuilder new_dict_builder ()
+public static void add_string (VariantBuilder builder, string key, string value)
+public static void add_int (VariantBuilder builder, string key, int value)
+public static void add_bool (VariantBuilder builder, string key, bool value)
+public static void add_double (VariantBuilder builder, string key, double value)
+public static void add_variant (VariantBuilder builder, string key, Variant value)
+```
+
+#### Dictionary Access Methods
+
+```vala
+public static bool has_key (Variant dict, string key)
+public static string get_string (Variant dict, string key, string? default_value = null)
+public static int get_int (Variant dict, string key, int default_value = 0)
+public static bool get_bool (Variant dict, string key, bool default_value = false)
+public static double get_double (Variant dict, string key, double default_value = 0.0)
+public static Variant? get_variant (Variant dict, string key)
+public static string[] get_string_array (Variant dict, string key)
+```
+
+#### Array Builder Methods
+
+```vala
+public static VariantBuilder new_array_builder (string element_type)
+public static void add_string_element (VariantBuilder builder, string value)
+public static void add_int_element (VariantBuilder builder, int value)
+public static void add_bool_element (VariantBuilder builder, bool value)
+public static void add_double_element (VariantBuilder builder, double value)
+public static void add_variant_element (VariantBuilder builder, Variant value)
+```
+
+#### Array Access Methods
+
+```vala
+public static int get_array_size (Variant array)
+public static string get_string_element (Variant array, int index)
+public static int get_int_element (Variant array, int index)
+public static bool get_bool_element (Variant array, int index)
+public static double get_double_element (Variant array, int index)
+public static Variant get_variant_element (Variant array, int index)
+```
+
+#### Conversion Methods
+
+```vala
+public static Json.Node? to_json (Variant variant)
+public static Variant? from_json (Json.Node node)
+```
+
 ## Resources Namespace
 
 ### Mcp.Resources.Provider
@@ -415,7 +520,7 @@ Interface for tool executors.
 
 ```vala
 public abstract Mcp.Tools.Types.ToolDefinition get_definition () throws Error
-public abstract async Mcp.Tools.Types.CallToolResult execute (Json.Object arguments) throws Error
+public abstract async Mcp.Tools.Types.CallToolResult execute (Variant arguments) throws Error
 ```
 
 ### Mcp.Tools.BaseExecutor
@@ -432,17 +537,17 @@ protected BaseExecutor (Mcp.Tools.Types.ToolDefinition definition)
 
 ```vala
 public virtual Mcp.Tools.Types.ToolDefinition get_definition () throws Error
-public async Mcp.Tools.Types.CallToolResult execute (Json.Object arguments) throws Error
-protected virtual void validate_arguments (Json.Object arguments) throws Error
+public async Mcp.Tools.Types.CallToolResult execute (Variant arguments) throws Error
+protected virtual void validate_arguments (Variant arguments) throws Error
 protected Mcp.Tools.Types.CallToolResult create_text_result (string text)
 protected Mcp.Tools.Types.CallToolResult create_text_results (string[] texts)
 protected Mcp.Tools.Types.CallToolResult create_error_result (Error error)
-protected Mcp.Tools.Types.CallToolResult create_structured_result (string text, Json.Object structured_data)
-protected string? get_string_arg (Json.Object arguments, string name, string? default_value = null)
-protected bool get_bool_arg (Json.Object arguments, string name, bool default_value = false)
-protected int get_int_arg (Json.Object arguments, string name, int default_value = 0)
-protected double get_double_arg (Json.Object arguments, string name, double default_value = 0.0)
-protected abstract async Mcp.Tools.Types.CallToolResult do_execute (Json.Object arguments) throws Error
+protected Mcp.Tools.Types.CallToolResult create_structured_result (string text, Variant structured_data)
+protected string? get_string_arg (Variant arguments, string name, string? default_value = null)
+protected bool get_bool_arg (Variant arguments, string name, bool default_value = false)
+protected int get_int_arg (Variant arguments, string name, int default_value = 0)
+protected double get_double_arg (Variant arguments, string name, double default_value = 0.0)
+protected abstract async Mcp.Tools.Types.CallToolResult do_execute (Variant arguments) throws Error
 ```
 
 ### Mcp.Tools.Manager
@@ -455,7 +560,7 @@ Manages tool executors and handles tool operations.
 public void register_executor (string name, Mcp.Tools.Executor executor)
 public void unregister_executor (string name)
 public async Gee.ArrayList<Mcp.Tools.Types.ToolDefinition> list_tools () throws Error
-public async Mcp.Tools.Types.CallToolResult call_tool (string name, Json.Object arguments) throws Error
+public async Mcp.Tools.Types.CallToolResult call_tool (string name, Variant arguments) throws Error
 ```
 
 ### Mcp.Tools.Types.ToolDefinition
@@ -465,7 +570,7 @@ Tool definition.
 #### Constructor
 
 ```vala
-public ToolDefinition (string name, Json.Object input_schema)
+public ToolDefinition (string name, Variant input_schema)
 ```
 
 #### Properties
@@ -474,8 +579,8 @@ public ToolDefinition (string name, Json.Object input_schema)
 public string name { get; set; }
 public string? title { get; set; }
 public string? description { get; set; }
-public Json.Object input_schema { get; set; }
-public Json.Object? output_schema { get; set; }
+public Variant input_schema { get; set; }
+public Variant? output_schema { get; set; }
 public Mcp.Tools.Types.ToolExecution? execution { get; set; }
 public Mcp.Tools.Types.ToolAnnotations? annotations { get; set; }
 ```
@@ -495,13 +600,14 @@ Result of calling a tool.
 
 ```vala
 public CallToolResult ()
+public CallToolResult (Gee.ArrayList<Mcp.Types.Common.ContentBlock> content)
 ```
 
 #### Properties
 
 ```vala
 public Gee.ArrayList<Mcp.Types.Common.ContentBlock> content { get; set; }
-public Json.Object? structured_content { get; set; }
+public Variant? structured_content { get; set; }
 public bool is_error { get; set; }
 ```
 
@@ -512,25 +618,52 @@ public Json.Node to_json ()
 public CallToolResult.from_json (Json.Node node) throws Error
 ```
 
-### Mcp.Tools.Types.ToolExecution
+### Mcp.Tools.Types.ToolExecutionContext
 
-Tool execution settings.
+Context for tool execution with progress tracking.
 
 #### Constructor
 
 ```vala
-public ToolExecution (string task_support = "forbidden")
+public ToolExecutionContext (string tool_name, Variant arguments)
 ```
 
 #### Properties
 
 ```vala
-public string task_support { get; set; }
+public string tool_name { get; construct; }
+public Variant arguments { get; construct; }
+public bool supports_progress { get; set; }
+public bool task_support { get; set; }
+```
+
+#### Methods
+
+```vala
+public void report_progress (Mcp.Tools.Types.ToolProgress progress)
+public void add_annotation (Mcp.Tools.Types.ToolAnnotation annotation)
+```
+
+### Mcp.Tools.Types.ToolProgress
+
+Progress information for long-running tools.
+
+#### Constructor
+
+```vala
+public ToolProgress (double progress, string? message = null)
+```
+
+#### Properties
+
+```vala
+public double progress { get; set; }
+public string? message { get; set; }
 ```
 
 ### Mcp.Tools.Types.ToolAnnotations
 
-Tool annotations.
+Tool execution annotations.
 
 #### Constructor
 
@@ -543,6 +676,41 @@ public ToolAnnotations ()
 ```vala
 public string? audience { get; set; }
 public double? priority { get; set; }
+public Gee.ArrayList<Mcp.Tools.Types.ToolAnnotation> annotations { get; set; }
+```
+
+### Mcp.Tools.Types.ToolAnnotation
+
+Individual tool annotation.
+
+#### Constructor
+
+```vala
+public ToolAnnotation (string type, Variant data)
+```
+
+#### Properties
+
+```vala
+public string type { get; set; }
+public Variant data { get; set; }
+```
+
+### Mcp.Tools.Types.ToolExecution
+
+Tool execution settings.
+
+#### Constructor
+
+```vala
+public ToolExecution (string task_support = "forbidden")
+```
+
+#### Properties
+
+```vala
+public string task_support { get; set; }
+public bool supports_progress { get; set; }
 ```
 
 ## Prompts Namespace
@@ -555,7 +723,7 @@ Interface for prompt templates.
 
 ```vala
 public abstract Mcp.Prompts.Types.PromptDefinition get_definition ()
-public abstract async Mcp.Prompts.Types.GetPromptResult get_prompt (Json.Object arguments) throws Error
+public abstract async Mcp.Prompts.Types.GetPromptResult get_prompt (Variant arguments) throws Error
 ```
 
 ### Mcp.Prompts.BaseTemplate
@@ -566,20 +734,21 @@ Base implementation for prompt templates.
 
 ```vala
 protected BaseTemplate (string name, string? title = null, string? description = null)
+protected BaseTemplate (string name, string? title, string? description, Gee.ArrayList<Mcp.Prompts.Types.PromptArgument> arguments)
 ```
 
 #### Methods
 
 ```vala
 public virtual Mcp.Prompts.Types.PromptDefinition get_definition ()
-public virtual async Mcp.Prompts.Types.GetPromptResult get_prompt (Json.Object arguments) throws Error
-protected virtual void validate_arguments (Json.Object arguments) throws Error
-protected virtual Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> generate_messages (Json.Object arguments)
+public virtual async Mcp.Prompts.Types.GetPromptResult get_prompt (Variant arguments) throws Error
+protected virtual void validate_arguments (Variant arguments) throws Error
+protected virtual Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> generate_messages (Variant arguments)
 protected void add_argument (string name, string? title = null, string? description = null, bool required = false)
-protected string substitute_variables (string template, Json.Object arguments)
-protected Mcp.Types.Common.TextContent create_text_content (string template, Json.Object arguments)
-protected Mcp.Prompts.Types.PromptMessage create_user_message (string template, Json.Object arguments)
-protected Mcp.Prompts.Types.PromptMessage create_assistant_message (string template, Json.Object arguments)
+protected string substitute_variables (string template, Variant arguments)
+protected Mcp.Types.Common.TextContent create_text_content (string template, Variant arguments)
+protected Mcp.Prompts.Types.PromptMessage create_user_message (string template, Variant arguments)
+protected Mcp.Prompts.Types.PromptMessage create_assistant_message (string template, Variant arguments)
 ```
 
 ### Mcp.Prompts.Manager
@@ -592,7 +761,7 @@ Manages prompt templates and handles prompt operations.
 public void register_template (string name, Mcp.Prompts.Template template)
 public void unregister_template (string name)
 public async Gee.ArrayList<Mcp.Prompts.Types.PromptDefinition> list_prompts () throws Error
-public async Mcp.Prompts.Types.GetPromptResult get_prompt (string name, Json.Object arguments) throws Error
+public async Mcp.Prompts.Types.GetPromptResult get_prompt (string name, Variant arguments) throws Error
 ```
 
 ### Mcp.Prompts.Types.PromptDefinition
@@ -760,7 +929,7 @@ public class MyResourceProvider : Mcp.Resources.BaseProvider {
     
     public override async Mcp.Types.Common.ResourceContents read_resource (string uri) throws Error {
         if (!storage.contains (uri)) {
-            throw new Mcp.Core.McpError.RESOURCE_NOT_FOUND ("Resource not found");
+            throw new Mcp.Core.Error.NOT_FOUND ("Resource not found");
         }
         
         return new Mcp.Types.Common.TextResourceContents (uri, storage[uri]);
@@ -773,29 +942,28 @@ public class MyResourceProvider : Mcp.Resources.BaseProvider {
 ```vala
 public class MyTool : Mcp.Tools.BaseExecutor {
     public MyTool () {
-        // Define input schema
-        var input_schema = new Json.Object ();
-        input_schema.set_string_member ("type", "object");
-        
-        var properties = new Json.Object ();
-        var param = new Json.Object ();
-        param.set_string_member ("type", "string");
-        param.set_string_member ("description", "Parameter description");
-        properties.set_object_member ("param", param);
+        // Define input schema using Variant
+        var input_schema = Mcp.Types.VariantUtils.new_dict_builder ();
+        input_schema.add ("{sv}", "type", new Variant.string ("object"));
         
-        input_schema.set_object_member ("properties", properties);
+        var properties = Mcp.Types.VariantUtils.new_dict_builder ();
+        var param = Mcp.Types.VariantUtils.new_dict_builder ();
+        param.add ("{sv}", "type", new Variant.string ("string"));
+        param.add ("{sv}", "description", new Variant.string ("Parameter description"));
+        properties.add ("{sv}", "param", param.end ());
         
-        var required = new Json.Array ();
-        required.add_string_element ("param");
-        input_schema.set_array_member ("required", required);
+        var required = new VariantBuilder (new VariantType ("as"));
+        required.add_value ("s", "param");
+        input_schema.add ("{sv}", "properties", properties.end ());
+        input_schema.add ("{sv}", "required", required.end ());
         
-        var definition = new Mcp.Tools.Types.ToolDefinition ("my_tool", input_schema);
+        var definition = new Mcp.Tools.Types.ToolDefinition ("my_tool", input_schema.end ());
         definition.description = "Description of my tool";
         
         base (definition);
     }
     
-    protected override async Mcp.Tools.Types.CallToolResult do_execute (Json.Object arguments) throws Error {
+    protected override async Mcp.Tools.Types.CallToolResult do_execute (Variant arguments) throws Error {
         string param = get_string_arg (arguments, "param");
         
         // Process input
@@ -816,30 +984,32 @@ public class MyTool : Mcp.Tools.BaseExecutor {
 ```vala
 public class MyPrompt : Mcp.Prompts.BaseTemplate {
     public MyPrompt () {
-        base ("my_prompt", "My Prompt", "Description of my prompt");
+        var arguments = new Gee.ArrayList<Mcp.Prompts.Types.PromptArgument> ();
+        
+        var topic_arg = new Mcp.Prompts.Types.PromptArgument ("topic");
+        topic_arg.description = "The topic to generate content for";
+        topic_arg.required = true;
+        arguments.add (topic_arg);
         
-        // Add arguments
-        add_argument ("topic", "Topic", "The topic to generate content for", true);
-        add_argument ("style", "Style", "Writing style", false, "neutral");
+        var style_arg = new Mcp.Prompts.Types.PromptArgument ("style");
+        style_arg.description = "Writing style";
+        arguments.add (style_arg);
+        
+        base ("my_prompt", "My Prompt", "Description of my prompt", arguments);
     }
     
-    protected override Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> generate_messages (Json.Object arguments) {
-        var messages = new Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> ();
+    protected override async Mcp.Prompts.Types.GetPromptResult do_render (Variant arguments) throws Error {
+        string topic = Mcp.Types.VariantUtils.get_string (arguments, "topic");
+        string style = Mcp.Types.VariantUtils.get_string (arguments, "style", "neutral");
         
-        string topic = get_string_arg (arguments, "topic");
-        string style = get_string_arg (arguments, "style", "neutral");
+        string template = """Generate %s content about %s.""".printf (style, topic);
         
-        string template = """Generate {{style}} content about {{topic}}.""";
+        var content = new Mcp.Types.Common.TextContent (template);
+        var message = new Mcp.Prompts.Types.PromptMessage ("user", content);
+        var messages = new Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> ();
+        messages.add (message);
         
-        messages.add (create_user_message (template, arguments));
-        return messages;
-    }
-    
-    private string? get_string_arg (Json.Object arguments, string name, string? default_value = null) {
-        if (arguments.has_member (name)) {
-            return arguments.get_string_member (name);
-        }
-        return default_value;
+        return new Mcp.Prompts.Types.GetPromptResult (messages);
     }
 }
 ```
@@ -942,7 +1112,7 @@ Mcp.Core.McpError
 ```vala
 try {
     // MCP operation
-} catch (Mcp.Core.McpError e) {
+} catch (Mcp.Core.Error e) {
     // Handle MCP-specific errors
     stderr.printf ("MCP Error [%d]: %s\n", e.code, e.message);
 } catch (GLib.Error e) {

+ 111 - 108
docs/developer-guide.md

@@ -92,12 +92,14 @@ public class MyServer : GLib.Object {
         var server_info = new Mcp.Types.Protocol.ServerInfo (
             "my-server",
             "1.0.0",
-            "My custom MCP server"
+            "My custom MCP server",
+            "https://my-server.example.com"
         );
         
         // Create capabilities
         var capabilities = new Mcp.Types.Protocol.ServerCapabilities ();
         capabilities.logging = true;
+        capabilities.completions = new Mcp.Types.Protocol.CompletionsCapabilities ();
         
         // Create server
         server = new Mcp.Core.Server (server_info, capabilities);
@@ -153,18 +155,19 @@ Tools are functions that clients can execute:
 
 ```vala
 // Tool definition
-var input_schema = new Json.Object ();
-input_schema.set_string_member ("type", "object");
+var input_schema = Mcp.Types.VariantUtils.new_dict_builder ();
+input_schema.add ("{sv}", "type", new Variant.string ("object"));
 
 var definition = new Mcp.Tools.Types.ToolDefinition (
     "my_tool",
-    input_schema
+    input_schema.end ()
 );
 
 // Tool execution result
-var result = new Mcp.Tools.Types.CallToolResult ();
 var content = new Mcp.Types.Common.TextContent ("Operation completed");
-result.content.add (content);
+var contents = new Gee.ArrayList<Mcp.Types.Common.ContentBlock> ();
+contents.add (content);
+var result = new Mcp.Tools.Types.CallToolResult (contents);
 ```
 
 ### Prompts
@@ -217,7 +220,7 @@ public class MyResourceProvider : Mcp.Resources.BaseProvider {
     
     public override async Mcp.Types.Common.ResourceContents read_resource (string uri) throws Error {
         if (!data_store.contains (uri)) {
-            throw new Mcp.Core.McpError.RESOURCE_NOT_FOUND ("Resource not found: %s".printf (uri));
+            throw new Mcp.Core.Error.NOT_FOUND ("Resource not found: %s".printf (uri));
         }
         
         return new Mcp.Types.Common.TextResourceContents (uri, data_store[uri]);
@@ -252,28 +255,27 @@ Implement the `Mcp.Tools.Executor` interface or extend `Mcp.Tools.BaseExecutor`:
 public class MyTool : Mcp.Tools.BaseExecutor {
     public MyTool () {
         // Define input schema
-        var input_schema = new Json.Object ();
-        input_schema.set_string_member ("type", "object");
+        var input_schema = Mcp.Types.VariantUtils.new_dict_builder ();
+        input_schema.add ("{sv}", "type", new Variant.string ("object"));
         
-        var properties = new Json.Object ();
-        var text_prop = new Json.Object ();
-        text_prop.set_string_member ("type", "string");
-        text_prop.set_string_member ("description", "Text to process");
-        properties.set_object_member ("text", text_prop);
+        var properties = Mcp.Types.VariantUtils.new_dict_builder ();
+        var text_prop = Mcp.Types.VariantUtils.new_dict_builder ();
+        text_prop.add ("{sv}", "type", new Variant.string ("string"));
+        text_prop.add ("{sv}", "description", new Variant.string ("Text to process"));
+        properties.add ("{sv}", "text", text_prop.end ());
         
-        input_schema.set_object_member ("properties", properties);
+        var required = new VariantBuilder (new VariantType ("as"));
+        required.add_value ("s", "text");
+        input_schema.add ("{sv}", "properties", properties.end ());
+        input_schema.add ("{sv}", "required", required.end ());
         
-        var required = new Json.Array ();
-        required.add_string_element ("text");
-        input_schema.set_array_member ("required", required);
-        
-        var definition = new Mcp.Tools.Types.ToolDefinition ("my_tool", input_schema);
+        var definition = new Mcp.Tools.Types.ToolDefinition ("my_tool", input_schema.end ());
         definition.description = "Processes text input";
         
         base (definition);
     }
     
-    protected override async Mcp.Tools.Types.CallToolResult do_execute (Json.Object arguments) throws Error {
+    protected override async Mcp.Tools.Types.CallToolResult do_execute (Variant arguments) throws Error {
         string text = get_string_arg (arguments, "text");
         
         // Process the text
@@ -294,12 +296,12 @@ server.tool_manager.register_executor ("my_tool", new MyTool ());
 Return structured data with your results:
 
 ```vala
-var structured_data = new Json.Object ();
-structured_data.set_string_member ("original", text);
-structured_data.set_string_member ("processed", processed);
-structured_data.set_int_member ("length", processed.length);
+var structured_data = Mcp.Types.VariantUtils.new_dict_builder ();
+structured_data.add ("{sv}", "original", new Variant.string (text));
+structured_data.add ("{sv}", "processed", new Variant.string (processed));
+structured_data.add ("{sv}", "length", new Variant.int32 (processed.length));
 
-return create_structured_result ("Text processed successfully", structured_data);
+return create_structured_result ("Text processed successfully", structured_data.end ());
 ```
 
 #### Error Handling
@@ -307,12 +309,12 @@ return create_structured_result ("Text processed successfully", structured_data)
 Handle errors gracefully:
 
 ```vala
-protected override async Mcp.Tools.Types.CallToolResult do_execute (Json.Object arguments) throws Error {
+protected override async Mcp.Tools.Types.CallToolResult do_execute (Variant arguments) throws Error {
     try {
         // Validate input
         string text = get_string_arg (arguments, "text");
         if (text.length == 0) {
-            throw new Mcp.Core.McpError.INVALID_PARAMS ("Text cannot be empty");
+            throw new Mcp.Core.Error.INVALID_PARAMS ("Text cannot be empty");
         }
         
         // Process
@@ -343,12 +345,12 @@ public class MyPrompt : Mcp.Prompts.BaseTemplate {
         add_argument ("length", "Length", "Desired length (short, medium, long)", false);
     }
     
-    protected override Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> generate_messages (Json.Object arguments) {
+    protected override async Mcp.Prompts.Types.GetPromptResult do_render (Variant arguments) throws Error {
         var messages = new Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> ();
         
-        string topic = get_string_arg (arguments, "topic");
-        string? style = get_string_arg (arguments, "style", "neutral");
-        string? length = get_string_arg (arguments, "length", "medium");
+        string topic = Mcp.Types.VariantUtils.get_string (arguments, "topic");
+        string? style = Mcp.Types.VariantUtils.get_string (arguments, "style", "neutral");
+        string? length = Mcp.Types.VariantUtils.get_string (arguments, "length", "medium");
         
         string template = """Generate {{style}} content about {{topic}}.
 Target length: {{length}}.
@@ -363,11 +365,8 @@ Please provide:
         return messages;
     }
     
-    private string? get_string_arg (Json.Object arguments, string name, string? default_value = null) {
-        if (arguments.has_member (name)) {
-            return arguments.get_string_member (name);
-        }
-        return default_value;
+    private string? get_string_arg (Variant arguments, string name, string? default_value = null) {
+        return Mcp.Types.VariantUtils.get_string (arguments, name, default_value);
     }
 }
 
@@ -402,25 +401,29 @@ Use creative language and imaginative expressions.
 Create conversations with multiple messages:
 
 ```vala
-protected override Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> generate_messages (Json.Object arguments) {
-    var messages = new Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> ();
-    
-    // System message
-    var system_content = new Mcp.Types.Common.TextContent (
-        "You are a helpful assistant specializing in {{topic}}."
-    );
-    var system_msg = new Mcp.Prompts.Types.PromptMessage ("system", system_content);
-    messages.add (system_msg);
-    
-    // User message
-    var user_content = new Mcp.Types.Common.TextContent (
-        "Tell me about {{topic}}."
-    );
-    var user_msg = new Mcp.Prompts.Types.PromptMessage ("user", user_content);
-    messages.add (user_msg);
-    
-    return messages;
-}
+protected override Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> generate_messages (Variant arguments) {
+        var messages = new Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> ();
+        
+        // System message
+        var system_content = new Mcp.Types.Common.TextContent (
+            "You are a helpful assistant specializing in %s.".printf (
+                Mcp.Types.VariantUtils.get_string (arguments, "topic")
+            )
+        );
+        var system_msg = new Mcp.Prompts.Types.PromptMessage ("system", system_content);
+        messages.add (system_msg);
+        
+        // User message
+        var user_content = new Mcp.Types.Common.TextContent (
+            "Tell me about %s.".printf (
+                Mcp.Types.VariantUtils.get_string (arguments, "topic")
+            )
+        );
+        var user_msg = new Mcp.Prompts.Types.PromptMessage ("user", user_content);
+        messages.add (user_msg);
+        
+        return messages;
+    }
 ```
 
 ## Best Practices
@@ -494,47 +497,46 @@ protected override Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> generate_messa
 
 1. **Validate all inputs**:
    ```vala
-   protected override void validate_arguments (Json.Object arguments) throws Error {
-       // Call base validation
-       base.validate_arguments (arguments);
-       
-       // Add custom validation
-       if (arguments.has_member ("custom_param")) {
-           string value = arguments.get_string_member ("custom_param");
-           if (!is_valid_custom_param (value)) {
-               throw new Mcp.Core.McpError.INVALID_PARAMS ("Invalid custom_param");
+   protected override void validate_arguments (Variant arguments) throws Error {
+           // Call base validation
+           base.validate_arguments (arguments);
+           
+           // Add custom validation
+           if (Mcp.Types.VariantUtils.has_key (arguments, "custom_param")) {
+               string value = Mcp.Types.VariantUtils.get_string (arguments, "custom_param");
+               if (!is_valid_custom_param (value)) {
+                   throw new Mcp.Core.Error.INVALID_PARAMS ("Invalid custom_param");
+               }
            }
        }
-   }
    ```
 
 2. **Use structured results**:
    ```vala
-   var structured_data = new Json.Object ();
-   structured_data.set_string_member ("status", "success");
-   structured_data.set_object_member ("result", result_object);
-   structured_data.set_double_member ("duration_ms", elapsed_ms);
+   var structured_data = Mcp.Types.VariantUtils.new_dict_builder ();
+   structured_data.add ("{sv}", "status", new Variant.string ("success"));
+   structured_data.add ("{sv}", "result", result_object);
+   structured_data.add ("{sv}", "duration_ms", new Variant.double (elapsed_ms));
    
-   return create_structured_result ("Operation completed", structured_data);
+   return create_structured_result ("Operation completed", structured_data.end ());
    ```
 
 3. **Handle long-running operations**:
    ```vala
-   protected override async Mcp.Tools.Types.CallToolResult do_execute (Json.Object arguments) throws Error {
-       // Start progress notification
-       var progress = new Json.Object ();
-       progress.set_string_member ("status", "processing");
-       send_progress_notification (progress);
-       
-       // Perform long operation
-       var result = yield perform_long_operation (arguments);
-       
-       // Final progress
-       progress.set_string_member ("status", "completed");
-       send_progress_notification (progress);
-       
-       return result;
-   }
+   protected override async Mcp.Tools.Types.CallToolResult do_execute (Variant arguments) throws Error {
+           // Start progress notification
+           var progress = new Mcp.Tools.Types.ToolProgress (0.0, "Processing...");
+           report_progress (progress);
+           
+           // Perform long operation
+           var result = yield perform_long_operation (arguments);
+           
+           // Final progress
+           var final_progress = new Mcp.Tools.Types.ToolProgress (1.0, "Completed");
+           report_progress (final_progress);
+           
+           return result;
+       }
    ```
 
 ### Prompt Design
@@ -572,17 +574,17 @@ The library provides these error types:
 ```vala
 try {
     // Your code
-} catch (Mcp.Core.McpError.INVALID_PARAMS e) {
+} catch (Mcp.Core.Error.INVALID_PARAMS e) {
     // Invalid method parameters
-} catch (Mcp.Core.McpError.METHOD_NOT_FOUND e) {
+} catch (Mcp.Core.Error.METHOD_NOT_FOUND e) {
     // Method doesn't exist
-} catch (Mcp.Core.McpError.RESOURCE_NOT_FOUND e) {
+} catch (Mcp.Core.Error.NOT_FOUND e) {
     // Resource doesn't exist
-} catch (Mcp.Core.McpError.INTERNAL_ERROR e) {
+} catch (Mcp.Core.Error.INTERNAL_ERROR e) {
     // Internal server error
-} catch (Mcp.Core.McpError.TRANSPORT_ERROR e) {
-    // Communication error
-} catch (Mcp.Core.McpError.PARSE_ERROR e) {
+} catch (Mcp.Core.Error.INVALID_ARGUMENT e) {
+    // Invalid argument
+} catch (Mcp.Core.Error.PARSE_ERROR e) {
     // JSON parsing error
 }
 ```
@@ -592,17 +594,17 @@ try {
 1. **Be specific in error messages**:
    ```vala
    // Good
-   throw new Mcp.Core.McpError.INVALID_PARAMS (
+   throw new Mcp.Core.Error.INVALID_PARAMS (
        "Temperature must be between -273.15 and 1000 Kelvin"
    );
    
    // Bad
-   throw new Mcp.Core.McpError.INVALID_PARAMS ("Invalid temperature");
+   throw new Mcp.Core.Error.INVALID_PARAMS ("Invalid temperature");
    ```
 
 2. **Include context in errors**:
    ```vala
-   throw new Mcp.Core.McpError.RESOURCE_NOT_FOUND (
+   throw new Mcp.Core.Error.NOT_FOUND (
        "File not found: %s (working directory: %s)".printf (path, working_dir)
    );
    ```
@@ -610,10 +612,10 @@ try {
 3. **Use appropriate error codes**:
    ```vala
    // Client error (bad request)
-   throw new Mcp.Core.McpError.INVALID_PARAMS ("...");
+   throw new Mcp.Core.Error.INVALID_PARAMS ("...");
    
    // Server error (something went wrong)
-   throw new Mcp.Core.McpError.INTERNAL_ERROR ("...");
+   throw new Mcp.Core.Error.INTERNAL_ERROR ("...");
    ```
 
 ## Testing and Debugging
@@ -625,8 +627,9 @@ Test your components individually:
 ```vala
 void test_tool_execution () {
     var tool = new MyTool ();
-    var arguments = new Json.Object ();
-    arguments.set_string_member ("text", "test");
+    var arguments = Mcp.Types.VariantUtils.new_dict_builder ();
+    arguments.add ("{sv}", "text", new Variant.string ("test"));
+    var args = arguments.end ();
     
     // Test synchronous execution
     tool.execute.begin (arguments, (obj, res) => {
@@ -666,8 +669,8 @@ void test_server_integration () {
 
 2. **Use print statements**:
    ```vala
-   public override async Mcp.Tools.Types.CallToolResult do_execute (Json.Object arguments) throws Error {
-       print ("Executing tool with arguments: %s\n", arguments.to_string (null));
+   public override async Mcp.Tools.Types.CallToolResult do_execute (Variant arguments) throws Error {
+       print ("Executing tool with arguments\n");
        
        var result = yield perform_operation (arguments);
        
@@ -784,13 +787,13 @@ var resource = new Mcp.Resources.Types.Resource ("file:///valid/path", "Name");
 // Validate schema
 public Mcp.Tools.Types.ToolDefinition get_definition () throws Error {
     if (definition.input_schema == null) {
-        throw new Mcp.Core.McpError.INTERNAL_ERROR ("Input schema not initialized");
+        throw new Mcp.Core.Error.INTERNAL_ERROR ("Input schema not initialized");
     }
     return definition;
 }
 
 // Check async execution
-protected override async Mcp.Tools.Types.CallToolResult do_execute (Json.Object arguments) throws Error {
+protected override async Mcp.Tools.Types.CallToolResult do_execute (Variant arguments) throws Error {
     // Always yield, even for sync operations
     var result = process_sync (arguments);
     return result;  // Missing yield!
@@ -808,8 +811,8 @@ protected override async Mcp.Tools.Types.CallToolResult do_execute (Json.Object
 **Solutions**:
 ```vala
 // Debug template
-protected override Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> generate_messages (Json.Object arguments) {
-    print ("Generating prompt with arguments: %s\n", arguments.to_string (null));
+protected override Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> generate_messages (Variant arguments) {
+    print ("Generating prompt with arguments\n");
     
     var messages = new Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> ();
     
@@ -873,14 +876,14 @@ public override async Mcp.Types.Common.BlobResourceContents read_resource (strin
 
 ```vala
 // Good: Non-blocking
-public override async Mcp.Tools.Types.CallToolResult do_execute (Json.Object arguments) throws Error {
+public override async Mcp.Tools.Types.CallToolResult do_execute (Variant arguments) throws Error {
     // Yield to allow other operations
     var result = yield perform_long_operation (arguments);
     return result;
 }
 
 // Bad: Blocking
-public override async Mcp.Tools.Types.CallToolResult do_execute (Json.Object arguments) throws Error {
+public override async Mcp.Tools.Types.CallToolResult do_execute (Variant arguments) throws Error {
     // This blocks the entire server!
     var result = perform_blocking_operation (arguments);
     return result;

+ 0 - 684
mcp-vala-architecture-design.md

@@ -1,684 +0,0 @@
-
-# Vala MCP Library Architecture Design
-
-## Overview
-
-This document outlines the architecture for a Vala library implementing the Model Context Protocol (MCP) version "2025-11-25" using jsonrpc-glib-1.0 for JSON-RPC communication. The design prioritizes developer experience while maintaining protocol compliance and performance.
-
-## Core Architecture
-
-### High-Level Design
-
-```
-┌─────────────────────────────────────────────────────────────┐
-│                    Application Layer                      │
-├─────────────────────────────────────────────────────────────┤
-│                    MCP Library API                      │
-├─────────────────────────────────────────────────────────────┤
-│  Resource Manager  │  Tool Manager  │  Prompt Manager   │
-├─────────────────────────────────────────────────────────────┤
-│              Jsonrpc.Server Implementation               │
-├─────────────────────────────────────────────────────────────┤
-│              jsonrpc-glib-1.0 + Json-Glib               │
-└─────────────────────────────────────────────────────────────┘
-```
-
-### Key Design Principles
-
-1. **Developer Experience First**: Simple, intuitive API with minimal boilerplate
-2. **Type Safety**: Leverage Vala's type system while using Json-Glib for JSON handling
-3. **Asynchronous Design**: Non-blocking operations throughout
-4. **Extensibility**: Clean interfaces for custom implementations
-5. **Protocol Compliance**: Full MCP v2025-11-25 specification support
-
-## Namespace Organization
-
-```
-Mcp
-├── Core                    // Core server infrastructure
-│   └── Server             // Main server class using Jsonrpc.Server
-├── Types                   // Shared data types and interfaces
-│   ├── Protocol            // MCP protocol types
-│   └── Common             // Common content types
-├── Resources              // Resource management
-│   ├── Manager
-│   ├── Provider
-│   └── Types
-├── Tools                 // Tool execution framework
-│   ├── Manager
-│   ├── Executor
-│   └── Types
-├── Prompts               // Prompt handling system
-│   ├── Manager
-│   ├── Template
-│   └── Types
-└── Core                  // Core error handling
-    └── Error
-```
-
-## Core Components
-
-### 1. Server Infrastructure
-
-#### Mcp.Core.Server
-
-```vala
-namespace Mcp.Core {
-    public class Server : Object {
-        // Server configuration
-        public ServerInfo server_info { get; construct; }
-        public ServerCapabilities capabilities { get; construct; }
-        
-        // Core managers
-        public ResourceManager resource_manager { get; construct; }
-        public ToolManager tool_manager { get; construct; }
-        public PromptManager prompt_manager { get; construct; }
-        
-        // Jsonrpc server instance
-        private Jsonrpc.Server jsonrpc_server;
-        
-        // Lifecycle
-        public signal void initialized ();
-        public signal void shutdown ();
-        
-        public async bool start () throws Error;
-        public async void stop ();
-        
-        // Jsonrpc method handlers
-        private Variant handle_initialize (Jsonrpc.Client client, string method, Variant params) throws Error;
-        private Variant handle_ping (Jsonrpc.Client client, string method, Variant params) throws Error;
-        private Variant handle_resources_list (Jsonrpc.Client client, string method, Variant params) throws Error;
-        // ... other handlers
-    }
-}
-```
-
-### 2. Jsonrpc Integration
-
-The library now uses the standard Jsonrpc.Server from jsonrpc-glib-1.0 for handling JSON-RPC communication. The custom JSON-RPC message types and transport layer have been removed in favor of the standard implementation.
-
-Key benefits:
-- Standard-compliant JSON-RPC 2.0 implementation
-- Robust error handling
-- Built-in support for async/await patterns
-- Proper STDIO transport handling
-
-#### Protocol Types
-
-```vala
-namespace Mcp.Types.Protocol {
-    public class ServerInfo : Object {
-        public string name { get; set; }
-        public string version { get; set; }
-        public string? description { get; set; }
-        public string? website_url { get; set; }
-    }
-    
-    public class ServerCapabilities : Object {
-        public bool logging { get; set; }
-        public bool completions { get; set; }
-        public PromptsCapabilities? prompts { get; set; }
-        public ResourcesCapabilities? resources { get; set; }
-        public ToolsCapabilities? tools { get; set; }
-    }
-    
-    public class PromptsCapabilities : Object {
-        public bool list_changed { get; set; }
-    }
-    
-    public class ResourcesCapabilities : Object {
-        public bool subscribe { get; set; }
-        public bool list_changed { get; set; }
-    }
-    
-    public class ToolsCapabilities : Object {
-        public bool list_changed { get; set; }
-    }
-}
-```
-
-### 4. Resource Management System
-
-#### Mcp.Resources.Manager
-
-```vala
-namespace Mcp.Resources {
-    public interface Provider : Object {
-        public abstract async List<Resource> list_resources (string? cursor) throws Error;
-        public abstract async ResourceContents read_resource (string uri) throws Error;
-        public virtual async void subscribe (string uri) throws Error { /* Optional */ }
-        public virtual async void unsubscribe (string uri) throws Error { /* Optional */ }
-    }
-    
-    public class Manager : Object {
-        private HashTable<string, Provider> providers;
-        
-        public void register_provider (string uri_scheme, Provider provider);
-        public void unregister_provider (string uri_scheme);
-        
-        // Protocol handlers
-        public async Json.Node handle_list (Json.Object params) throws Error;
-        public async Json.Node handle_read (Json.Object params) throws Error;
-        public async Json.Node handle_subscribe (Json.Object params) throws Error;
-        public async Json.Node handle_unsubscribe (Json.Object params) throws Error;
-        
-        // Notifications
-        public void notify_list_changed ();
-        public void notify_resource_updated (string uri);
-    }
-}
-```
-
-#### Resource Types
-
-```vala
-namespace Mcp.Resources.Types {
-    public class Resource : Object {
-        public string uri { get; set; }
-        public string name { get; set; }
-        public string? title { get; set; }
-        public string? description { get; set; }
-        public string? mime_type { get; set; }
-        public Annotations? annotations { get; set; }
-        public int64? size { get; set; }
-    }
-    
-    public class ResourceContents : Object {
-        public string uri { get; set; }
-        public string? mime_type { get; set; }
-    }
-    
-    public class TextResourceContents : ResourceContents {
-        public string text { get; set; }
-    }
-    
-    public class BlobResourceContents : ResourceContents {
-        public string blob { get; set; } // Base64 encoded
-    }
-}
-```
-
-### 5. Tool Execution Framework
-
-#### Mcp.Tools.Manager
-
-```vala
-namespace Mcp.Tools {
-    public interface Executor : Object {
-        public abstract ToolDefinition get_definition ();
-        public abstract async CallToolResult execute (Json.Object arguments) throws Error;
-    }
-    
-    public class Manager : Object {
-        private HashTable<string, Executor> executors;
-        
-        public void register_executor (string name, Executor executor);
-        public void unregister_executor (string name);
-        
-        // Protocol handlers
-        public async Json.Node handle_list (Json.Object params) throws Error;
-        public async Json.Node handle_call (Json.Object params) throws Error;
-        
-        // Notifications
-        public void notify_list_changed ();
-    }
-}
-```
-
-#### Tool Types
-
-```vala
-namespace Mcp.Tools.Types {
-    public class ToolDefinition : Object {
-        public string name { get; set; }
-        public string? title { get; set; }
-        public string? description { get; set; }
-        public Json.Object input_schema { get; set; }
-        public Json.Object? output_schema { get; set; }
-        public ToolExecution? execution { get; set; }
-        public ToolAnnotations? annotations { get; set; }
-    }
-    
-    public class CallToolResult : Object {
-        public List<ContentBlock> content { get; set; }
-        public Json.Object? structured_content { get; set; }
-        public bool is_error { get; set; default = false; }
-    }
-    
-    public class ToolExecution : Object {
-        public string task_support { get; set; default = "forbidden"; } // forbidden, optional, required
-    }
-}
-```
-
-### 6. Prompt Handling System
-
-#### Mcp.Prompts.Manager
-
-```vala
-namespace Mcp.Prompts {
-    public interface Template : Object {
-        public abstract PromptDefinition get_definition ();
-        public abstract async GetPromptResult get_prompt (Json.Object arguments) throws Error;
-    }
-    
-    public class Manager : Object {
-        private HashTable<string, Template> templates;
-        
-        public void register_template (string name, Template template);
-        public void unregister_template (string name);
-        
-        // Protocol handlers
-        public async Json.Node handle_list (Json.Object params) throws Error;
-        public async Json.Node handle_get (Json.Object params) throws Error;
-        
-        // Notifications
-        public void notify_list_changed ();
-    }
-}
-```
-
-#### Prompt Types
-
-```vala
-namespace Mcp.Prompts.Types {
-    public class PromptDefinition : Object {
-        public string name { get; set; }
-        public string? title { get; set; }
-        public string? description { get; set; }
-        public List<PromptArgument> arguments { get; set; }
-    }
-    
-    public class PromptArgument : Object {
-        public string name { get; set; }
-        public string? title { get; set; }
-        public string? description { get; set; }
-        public bool required { get; set; default = false; }
-    }
-    
-    public class GetPromptResult : Object {
-        public string? description { get; set; }
-        public List<PromptMessage> messages { get; set; }
-    }
-    
-    public class PromptMessage : Object {
-        public string role { get; set; } // "user" | "assistant"
-        public ContentBlock content { get; set; }
-    }
-}
-```
-
-### 7. Content System
-
-```vala
-namespace Mcp.Types.Common {
-    public interface ContentBlock : Object {
-        public string type { get; }
-    }
-    
-    public class TextContent : Object, ContentBlock {
-        public string type { get; construct; default = "text"; }
-        public string text { get; set; }
-        public Annotations? annotations { get; set; }
-    }
-    
-    public class ImageContent : Object, ContentBlock {
-        public string type { get; construct; default = "image"; }
-        public string data { get; set; } // Base64 encoded
-        public string mime_type { get; set; }
-        public Annotations? annotations { get; set; }
-    }
-    
-    public class ResourceLink : Object, ContentBlock {
-        public string type { get; construct; default = "resource_link"; }
-        public string uri { get; set; }
-        public string name { get; set; }
-        public string? title { get; set; }
-        public string? description { get; set; }
-        public string? mime_type { get; set; }
-        public Annotations? annotations { get; set; }
-    }
-    
-    public class EmbeddedResource : Object, ContentBlock {
-        public string type { get; construct; default = "resource"; }
-        public ResourceContents resource { get; set; }
-        public Annotations? annotations { get; set; }
-    }
-}
-```
-
-### 8. Error Handling
-
-```vala
-namespace Mcp.Core {
-    public errordomain McpError {
-        PARSE_ERROR,
-        INVALID_REQUEST,
-        METHOD_NOT_FOUND,
-        INVALID_PARAMS,
-        INTERNAL_ERROR,
-        RESOURCE_NOT_FOUND,
-        TOOL_EXECUTION_FAILED,
-        PROMPT_NOT_FOUND
-    }
-    
-    public class ErrorHandler : Object {
-        public static Json.Node create_error_response (string id, McpError error);
-        public static Json.Node create_error_notification (McpError error);
-        public static McpError from_json_code (int code, string message);
-    }
-}
-```
-
-### 9. Event System
-
-```vala
-namespace Mcp.Notifications {
-    public class Emitter : Object {
-        public signal void resource_list_changed ();
-        public signal void resource_updated (string uri);
-        public signal void tool_list_changed ();
-        public signal void prompt_list_changed ();
-        public signal void logging_message (LoggingLevel level, string? logger, Json.Node data);
-        public signal void progress (ProgressToken token, double progress, double? total, string? message);
-    }
-    
-    public enum LoggingLevel {
-        DEBUG,
-        INFO,
-        NOTICE,
-        WARNING,
-        ERROR,
-        CRITICAL,
-        ALERT,
-        EMERGENCY
-    }
-}
-```
-
-## Public API Design
-
-### Simple Server Creation
-
-```vala
-using Mcp;
-
-public class MyServer : Object {
-    private Mcp.Core.Server server;
-    
-    public MyServer () {
-        // Create server with basic info
-        server = new Mcp.Core.Server (
-            new Mcp.Types.Protocol.ServerInfo () {
-                name = "my-mcp-server",
-                version = "1.0.0",
-                description = "My awesome MCP server"
-            },
-            new Mcp.Types.Protocol.ServerCapabilities () {
-                resources = new Mcp.Types.Protocol.ResourcesCapabilities () {
-                    subscribe = true,
-                    list_changed = true
-                },
-                tools = new Mcp.Types.Protocol.ToolsCapabilities () {
-                    list_changed = true
-                }
-            }
-        );
-        
-        // Register providers
-        setup_resources ();
-        setup_tools ();
-        setup_prompts ();
-    }
-    
-    private void setup_resources () {
-        server.resource_manager.register_provider ("file", new FileResourceProvider ());
-        server.resource_manager.register_provider ("http", new HttpResourceProvider ());
-    }
-    
-    private void setup_tools () {
-        server.tool_manager.register_executor ("calculate", new CalculateTool ());
-        server.tool_manager.register_executor ("fetch", new FetchTool ());
-    }
-    
-    private void setup_prompts () {
-        server.prompt_manager.register_template ("summarize", new SummarizePrompt ());
-    }
-    
-    public async int run () {
-        try {
-            yield server.start ();
-            new MainLoop ().run ();
-            return 0;
-        } catch (Error e) {
-            stderr.printf ("Server error: %s\n", e.message);
-            return 1;
-        }
-    }
-}
-```
-
-### Resource Provider Example
-
-```vala
-using Mcp;
-
-public class FileResourceProvider : Object, Mcp.Resources.Provider {
-    public async List<Mcp.Resources.Types.Resource> list_resources (string? cursor) throws Error {
-        var resources = new List<Mcp.Resources.Types.Resource> ();
-        
-        // List files in current directory
-        var dir = File.new_for_path (".");
-        var enumerator = await dir.enumerate_children_async (
-            "standard::name,standard::type,standard::size",
-            FileQueryInfoFlags.NONE
-        );
-        
-        FileInfo file_info;
-        while ((file_info = yield enumerator.next_file_async ()) != null) {
-            if (file_info.get_file_type () == FileType.REGULAR) {
-                var file = enumerator.get_child (file_info);
-                var resource = new Mcp.Resources.Types.Resource () {
-                    uri = file.get_uri (),
-                    name = file_info.get_name (),
-                    mime_type = guess_mime_type (file_info.get_name ()),
-                    size = file_info.get_size ()
-                };
-                resources.append (resource);
-            }
-        }
-        
-        return resources;
-    }
-    
-    public async Mcp.Resources.Types.ResourceContents read_resource (string uri) throws Error {
-        var file = File.new_for_uri (uri);
-        if (!file.query_exists ()) {
-            throw new Mcp.Core.McpError.RESOURCE_NOT_FOUND ("File not found: %s".printf (uri));
-        }
-        
-        uint8[] contents;
-        yield file.load_contents_async (null, out contents);
-        
-        var text = (string) contents;
-        return new Mcp.Resources.Types.TextResourceContents () {
-            uri = uri,
-            text = text,
-            mime_type = guess_mime_type (file.get_basename ())
-        };
-    }
-}
-```
-
-### Tool Executor Example
-
-```vala
-using Mcp;
-
-public class CalculateTool : Object, Mcp.Tools.Executor {
-    public Mcp.Tools.Types.ToolDefinition get_definition () {
-        return new Mcp.Tools.Types.ToolDefinition () {
-            name = "calculate",
-            description = "Perform mathematical calculations",
-            input_schema = new Json.Object () {
-                type = "object",
-                properties = new Json.Object () {
-                    expression = new Json.Object () {
-                        type = "string",
-                        description = "Mathematical expression to evaluate"
-                    }
-                },
-                required = new string[] { "expression" }
-            }
-        };
-    }
-    
-    public async Mcp.Tools.Types.CallToolResult execute (Json.Object arguments) throws Error {
-        var expression = arguments.get_string_member ("expression");
-        
-        try {
-            // Simple expression evaluation (in real implementation, use proper parser)
-            var result = evaluate_expression (expression);
-            
-            var content = new Mcp.Types.Common.TextContent () {
-                text = "Result: %s = %s".printf (expression, result.to_string ())
-            };
-            
-            var contents = new List<Mcp.Types.Common.ContentBlock> ();
-            contents.append (content);
-            
-            return new Mcp.Tools.Types.CallToolResult () {
-                content = contents,
-                structured_content = new Json.Object () {
-                    expression = expression,
-                    result = result.to_string ()
-                }
-            };
-        } catch (Error e) {
-            var content = new Mcp.Types.Common.TextContent () {
-                text = "Error evaluating expression: %s".printf (e.message)
-            };
-            
-            var contents = new List<Mcp.Types.Common.ContentBlock> ();
-            contents.append (content);
-            
-            return new Mcp.Tools.Types.CallToolResult () {
-                content = contents,
-                is_error = true
-            };
-        }
-    }
-}
-```
-
-## Build System
-
-### Meson Build Configuration
-
-```meson
-project('mcp-vala', 'vala', 'c',
-  version: '1.0.0',
-  default_options: ['warning_level=2', 'werror=false']
-)
-
-# Dependencies
-glib_dep = dependency('glib-2.0', version: '>= 2.70')
-gobject_dep = dependency('gobject-2.0', version: '>= 2.70')
-gio_dep = dependency('gio-2.0', version: '>= 2.70')
-json_glib_dep = dependency('json-glib-1.0', version: '>= 1.6')
-jsonrpc_glib_dep = dependency('jsonrpc-glib-1.0', version: '>= 3.34')
-gio_unix_dep = dependency('gio-unix-2.0')
-
-# Library configuration
-mcp_sources = [
-  'src/core/server.vala',
-  'src/core/error.vala',
-  'src/types/protocol.vala',
-  'src/types/common.vala',
-  'src/resources/manager.vala',
-  'src/resources/provider.vala',
-  'src/resources/types.vala',
-  'src/tools/manager.vala',
-  'src/tools/executor.vala',
-  'src/tools/types.vala',
-  'src/prompts/manager.vala',
-  'src/prompts/template.vala',
-  'src/prompts/types.vala'
-]
-
-mcp_vala_args = [
-  '--target-glib=2.70',
-  '--pkg', 'glib-2.0',
-  '--pkg', 'gobject-2.0',
-  '--pkg', 'gio-2.0',
-  '--pkg', 'json-glib-1.0',
-  '--pkg', 'jsonrpc-glib-1.0',
-  '--pkg', 'gio-unix-2.0'
-]
-
-# Build library
-mcp_lib = shared_library(
-  'mcp-vala',
-  mcp_sources,
-  dependencies: [
-    glib_dep,
-    gobject_dep,
-    gio_dep,
-    json_glib_dep,
-    jsonrpc_glib_dep,
-    gio_unix_dep
-  ],
-  vala_args: mcp_vala_args,
-  install: true,
-  install_dir: get_option('libdir')
-)
-
-# Install headers
-install_headers(
-  'mcp-vala.h',
-  install_dir: join_paths(get_option('includedir'), 'mcp-vala')
-)
-
-# VAPI file
-mcp_vapi = custom_target(
-  'mcp-vala.vapi',
-  input: mcp_sources,
-  output: 'mcp-vala.vapi',
-  command: [find_program('valac'), '--vapi', '@OUTPUT@'] + mcp_vala_args + ['@INPUT@'],
-  install: true,
-  install_dir: get_option('datadir') / 'vala' / 'vapi'
-)
-
-# PC file
-pkg_mod = import('pkgconfig')
-pkg_mod.generate(
-  libraries: mcp_lib,
-  version: meson.project_version(),
-  name: 'mcp-vala',
-  description: 'Vala library for Model Context Protocol',
-  filebase: 'mcp-vala',
-  subdirs: 'mcp-vala'
-)
-```
-
-## Implementation Considerations
-
-### JSON Handling Strategy
-
-1. **Use Json-Glib for data structures**: Use Json.Node, Json.Object, and Json.Array for MCP protocol types
-2. **Use GLib.Variant for Jsonrpc communication**: Convert between Json.Node and GLib.Variant when interfacing with Jsonrpc.Server
-3. **Type-safe serialization**: Create helper methods for converting between Vala objects and JSON
-4. **Validation**: Use Json-Glib's schema validation where applicable
-5. **Memory management**: Leverage Vala's reference counting for JSON objects
-
-### Asynchronous Operations
-
-1. **Gio.Async patterns**: Use async/await throughout for non-blocking operations
-2. **Jsonrpc integration**: Properly handle async method calls with Jsonrpc.Server
-
-### Jsonrpc Integration Benefits
-
-1. **Standard compliance**: Full JSON-RPC 2.0 compliance through jsonrpc-glib-1.0
-2. **Robust error handling**: Built-in error handling and response formatting
-3. **IO handling**: Proper STDIO transport handling with buffering and error recovery
-4. **Performance**: Optimized JSON parsing and message handling

+ 0 - 2
test.sh

@@ -1,2 +0,0 @@
-#!/usr/bin/bash
-strace -o trace.log -e trace=read,write -s 4096 ./builddir/examples/filesystem-server

+ 0 - 240
test_calculator_comprehensive.py

@@ -1,240 +0,0 @@
-#!/usr/bin/env python3
-"""
-Comprehensive test for calculator-server to verify the fix
-"""
-
-import subprocess
-import time
-import json
-import sys
-import os
-import threading
-import queue
-
-class MCPServerTester:
-    def __init__(self, server_path):
-        self.server_path = server_path
-        self.server_process = None
-        self.message_queue = queue.Queue()
-        
-    def start_server(self):
-        """Start MCP server process"""
-        print(f"Starting MCP server: {self.server_path}")
-        self.server_process = subprocess.Popen(
-            [self.server_path],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            text=False,
-            bufsize=0
-        )
-        
-        # Start thread to read stderr
-        stderr_thread = threading.Thread(target=self._read_stderr)
-        stderr_thread.daemon = True
-        stderr_thread.start()
-        
-        # Start thread to read stdout
-        stdout_thread = threading.Thread(target=self._read_stdout)
-        stdout_thread.daemon = True
-        stdout_thread.start()
-        
-        time.sleep(1)
-        
-    def _read_stderr(self):
-        """Read stderr output from server"""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                line = self.server_process.stderr.readline()
-                if line:
-                    print(f"SERVER STDERR: {line.decode().strip()}")
-            except:
-                break
-                
-    def _read_stdout(self):
-        """Read stdout output from server with proper Content-Length parsing"""
-        buffer = b""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                # Read line by line
-                line = self.server_process.stdout.readline()
-                if not line:
-                    break
-                    
-                buffer += line
-                
-                # Check if we have a complete message
-                if b'\n' in buffer:
-                    # Split on newline to get individual messages
-                    lines = buffer.split(b'\n')
-                    for i, msg_line in enumerate(lines):
-                        if msg_line.strip():
-                            try:
-                                # Try to parse as JSON
-                                message = json.loads(msg_line.decode())
-                                self.message_queue.put(message)
-                            except json.JSONDecodeError as e:
-                                print(f"JSON DECODE ERROR: {e}")
-                    # Keep the last incomplete line if any
-                    if lines and not lines[-1].strip():
-                        buffer = lines[-1]
-                    else:
-                        buffer = b""
-            except:
-                break
-                        
-    def send_jsonrpc_request(self, method, params=None, id=1):
-        """Send a JSON-RPC request"""
-        request = {
-            "jsonrpc": "2.0",
-            "id": id,
-            "method": method,
-            "params": params or {}
-        }
-        
-        request_str = json.dumps(request)
-        message = f"{request_str}\n"
-        
-        self.server_process.stdin.write(message.encode())
-        self.server_process.stdin.flush()
-        
-        try:
-            response = self.message_queue.get(timeout=10)
-            return response
-        except queue.Empty:
-            print("TIMEOUT: No response received")
-            return None
-            
-    def test_operation(self, operation, operand1, operand2, expected_result):
-        """Test a specific operation"""
-        print(f"\n=== Testing {operation} with {operand1} and {operand2} ===")
-        
-        params = {
-            "name": "basic_calculator",
-            "arguments": {
-                "operation": operation,
-                "operand1": operand1,
-                "operand2": operand2
-            },
-            "_meta": {
-                "progressToken": 0
-            }
-        }
-        
-        response = self.send_jsonrpc_request("tools/call", params, id=1)
-        
-        if response and "result" in response:
-            result = response["result"]
-            if "content" in result and len(result["content"]) > 0:
-                content = result["content"][0]
-                if "text" in content:
-                    result_text = content["text"]
-                    print(f"Result text: {result_text}")
-                    
-                    # Check if result matches expected
-                    if str(expected_result) in result_text:
-                        print(f"✓ Correct result: {expected_result}")
-                    else:
-                        print(f"✗ Incorrect result: expected {expected_result}, got {result_text}")
-                        
-            if "structured_content" in result and isinstance(result["structured_content"], dict):
-                structured = result["structured_content"]
-                if 'result' in structured:
-                    actual_result = structured['result']
-                    print(f"Structured result: {actual_result}")
-                    
-                    # Check if result matches expected
-                    if abs(actual_result - expected_result) < 0.001:
-                        print(f"✓ Correct calculation: {actual_result}")
-                    else:
-                        print(f"✗ Incorrect calculation: expected {expected_result}, got {actual_result}")
-                        
-                    # Check operands
-                    if 'operand1' in structured:
-                        print(f"operand1 in result: {structured['operand1']}")
-                    if 'operand2' in structured:
-                        print(f"operand2 in result: {structured['operand2']}")
-        else:
-            print("✗ No response or error in response")
-            
-    def stop_server(self):
-        """Stop MCP server process"""
-        if self.server_process:
-            print("\nStopping server...")
-            self.server_process.terminate()
-            try:
-                self.server_process.wait(timeout=5)
-            except subprocess.TimeoutExpired:
-                self.server_process.kill()
-            self.server_process = None
-
-def main():
-    if len(sys.argv) != 2:
-        print("Usage: python3 test_calculator_comprehensive.py <server-executable>")
-        sys.exit(1)
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        sys.exit(1)
-        
-    tester = MCPServerTester(server_path)
-    
-    try:
-        tester.start_server()
-        time.sleep(2)
-        
-        # Initialize first
-        print("\nInitializing server...")
-        init_params = {
-            "protocolVersion": "2025-11-25",
-            "capabilities": {},
-            "clientInfo": {
-                "name": "test-client",
-                "version": "1.0.0"
-            }
-        }
-        init_response = tester.send_jsonrpc_request("initialize", init_params, id=0)
-        
-        if init_response:
-            print("✓ Server initialized successfully")
-            
-            # Test different operations with different number types
-            test_cases = [
-                # (operation, operand1, operand2, expected_result)
-                ("add", 2, 3, 5),
-                ("add", 2.5, 3.7, 6.2),
-                ("add", -5, 10, 5),
-                ("subtract", 10, 3, 7),
-                ("multiply", 4, 5, 20),
-                ("divide", 20, 4, 5),
-                ("power", 2, 3, 8),
-                ("modulo", 10, 3, 1),
-                # Test with integer types
-                ("add", 2, 3, 5),
-                ("add", 100, 200, 300),
-                # Test with float types
-                ("add", 2.5, 3.5, 6.0),
-                ("add", -2.5, 3.5, 1.0),
-                ("multiply", 1.5, 2.5, 3.75),
-                ("divide", 10.0, 2.5, 4.0),
-            ]
-            
-            for operation, operand1, operand2, expected in test_cases:
-                tester.test_operation(operation, operand1, operand2, expected)
-                
-            print("\n✓ All calculator tests completed successfully")
-        else:
-            print("✗ Failed to initialize server")
-            
-    except KeyboardInterrupt:
-        print("\nTest interrupted by user")
-    except Exception as e:
-        print(f"\nError during test: {e}")
-        import traceback
-        traceback.print_exc()
-    finally:
-        tester.stop_server()
-
-if __name__ == "__main__":
-    main()

+ 0 - 243
test_calculator_debug.py

@@ -1,243 +0,0 @@
-#!/usr/bin/env python3
-"""
-Debug script for calculator-server to trace JSON-RPC request handling
-"""
-
-import subprocess
-import time
-import json
-import sys
-import os
-import threading
-import queue
-
-class MCPServerTester:
-    def __init__(self, server_path):
-        self.server_path = server_path
-        self.server_process = None
-        self.message_queue = queue.Queue()
-        
-    def start_server(self):
-        """Start MCP server process"""
-        print(f"Starting MCP server: {self.server_path}")
-        self.server_process = subprocess.Popen(
-            [self.server_path],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            text=False,
-            bufsize=0
-        )
-        
-        # Start thread to read stderr
-        stderr_thread = threading.Thread(target=self._read_stderr)
-        stderr_thread.daemon = True
-        stderr_thread.start()
-        
-        # Start thread to read stdout
-        stdout_thread = threading.Thread(target=self._read_stdout)
-        stdout_thread.daemon = True
-        stdout_thread.start()
-        
-        time.sleep(1)
-        
-    def _read_stderr(self):
-        """Read stderr output from server"""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                line = self.server_process.stderr.readline()
-                if line:
-                    print(f"SERVER STDERR: {line.decode().strip()}")
-            except:
-                break
-                
-    def _read_stdout(self):
-        """Read stdout output from server with proper Content-Length parsing"""
-        buffer = b""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                # Read line by line
-                line = self.server_process.stdout.readline()
-                if not line:
-                    break
-                    
-                buffer += line
-                
-                # Check if we have a complete message
-                if b'\n' in buffer:
-                    # Split on newline to get individual messages
-                    lines = buffer.split(b'\n')
-                    for i, msg_line in enumerate(lines):
-                        if msg_line.strip():
-                            try:
-                                # Try to parse as JSON
-                                message = json.loads(msg_line.decode())
-                                self.message_queue.put(message)
-                                print(f"RECEIVED: {json.dumps(message, indent=2)}")
-                            except json.JSONDecodeError as e:
-                                print(f"JSON DECODE ERROR: {e}")
-                                print(f"RAW: {msg_line}")
-                    # Keep the last incomplete line if any
-                    if lines and not lines[-1].strip():
-                        buffer = lines[-1]
-                    else:
-                        buffer = b""
-            except:
-                break
-                        
-    def send_jsonrpc_request(self, method, params=None, id=1):
-        """Send a JSON-RPC request with Content-Length header"""
-        request = {
-            "jsonrpc": "2.0",
-            "id": id,
-            "method": method,
-            "params": params or {}
-        }
-        
-        request_str = json.dumps(request)
-        # Use the format from test_resources_fixed.py which works
-        message = f"{request_str}\n"
-        
-        print(f"SENDING: {json.dumps(request, indent=2)}")
-        print(f"RAW: {message.encode()}")
-        
-        self.server_process.stdin.write(message.encode())
-        self.server_process.stdin.flush()
-        
-        try:
-            response = self.message_queue.get(timeout=10)
-            return response
-        except queue.Empty:
-            print("TIMEOUT: No response received")
-            return None
-            
-    def test_calculator_with_debug(self):
-        """Test calculator with the exact request that's failing"""
-        print("\n=== Testing Calculator with Debug ===")
-        
-        # Test with the exact request from the issue
-        test_request = {
-            "jsonrpc": "2.0",
-            "id": 1,
-            "method": "tools/call",
-            "params": {
-                "name": "basic_calculator",
-                "arguments": {
-                    "operation": "add",
-                    "operand1": 2,
-                    "operand2": 3
-                },
-                "_meta": {
-                    "progressToken": 0
-                }
-            }
-        }
-        
-        print(f"\nTesting with request:")
-        print(json.dumps(test_request, indent=2))
-        
-        response = self.send_jsonrpc_request("tools/call", test_request["params"], id=1)
-        
-        if response:
-            print(f"\nResponse received:")
-            print(json.dumps(response, indent=2))
-            
-            if "result" in response:
-                result = response["result"]
-                if "content" in result and len(result["content"]) > 0:
-                    content = result["content"][0]
-                    if "text" in content:
-                        print(f"\nResult text: {content['text']}")
-                    if "structured_content" in result:
-                        print(f"Structured content: {result['structured_content']}")
-                        
-                        # Check if operands are correctly parsed
-                        if isinstance(result['structured_content'], dict):
-                            if 'operand1' in result['structured_content']:
-                                print(f"operand1 in result: {result['structured_content']['operand1']}")
-                            if 'operand2' in result['structured_content']:
-                                print(f"operand2 in result: {result['structured_content']['operand2']}")
-                            if 'result' in result['structured_content']:
-                                print(f"calculation result: {result['structured_content']['result']}")
-                else:
-                    print("No content in response")
-            elif "error" in response:
-                print(f"Error in response: {response['error']}")
-        else:
-            print("No response received")
-            
-    def test_simple_request(self):
-        """Test with a simpler request"""
-        print("\n=== Testing Simple Request ===")
-        
-        # Test tools/list first
-        print("\nTesting tools/list...")
-        list_response = self.send_jsonrpc_request("tools/list", id=2)
-        
-        if list_response:
-            print(f"Tools list response:")
-            print(json.dumps(list_response, indent=2))
-        else:
-            print("No response for tools/list")
-            
-    def stop_server(self):
-        """Stop MCP server process"""
-        if self.server_process:
-            print("\nStopping server...")
-            self.server_process.terminate()
-            try:
-                self.server_process.wait(timeout=5)
-            except subprocess.TimeoutExpired:
-                self.server_process.kill()
-            self.server_process = None
-
-def main():
-    if len(sys.argv) != 2:
-        print("Usage: python3 test_calculator_debug.py <server-executable>")
-        sys.exit(1)
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        sys.exit(1)
-        
-    tester = MCPServerTester(server_path)
-    
-    try:
-        tester.start_server()
-        time.sleep(2)
-        
-        # Initialize first
-        print("\nInitializing server...")
-        init_params = {
-            "protocolVersion": "2025-11-25",
-            "capabilities": {},
-            "clientInfo": {
-                "name": "test-client",
-                "version": "1.0.0"
-            }
-        }
-        init_response = tester.send_jsonrpc_request("initialize", init_params, id=0)
-        
-        if init_response:
-            print("✓ Server initialized successfully")
-            
-            # Test simple request first
-            tester.test_simple_request()
-            
-            # Test calculator with debug
-            tester.test_calculator_with_debug()
-        else:
-            print("✗ Failed to initialize server")
-            
-    except KeyboardInterrupt:
-        print("\nTest interrupted by user")
-    except Exception as e:
-        print(f"\nError during test: {e}")
-        import traceback
-        traceback.print_exc()
-    finally:
-        tester.stop_server()
-
-if __name__ == "__main__":
-    main()

+ 0 - 196
test_content_length.py

@@ -1,196 +0,0 @@
-#!/usr/bin/env python3
-"""
-Test MCP server connection with proper Content-Length headers
-"""
-
-import subprocess
-import time
-import json
-import sys
-import os
-import threading
-import queue
-import tempfile
-
-class MCPServerTester:
-    def __init__(self, server_path):
-        self.server_path = server_path
-        self.server_process = None
-        self.message_queue = queue.Queue()
-        
-    def start_server(self):
-        """Start MCP server process"""
-        print(f"Starting MCP server: {self.server_path}")
-        self.server_process = subprocess.Popen(
-            [self.server_path],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            text=False,  # Use binary mode for proper handling
-            bufsize=0
-        )
-        
-        # Start thread to read stderr
-        stderr_thread = threading.Thread(target=self._read_stderr)
-        stderr_thread.daemon = True
-        stderr_thread.start()
-        
-        # Start thread to read stdout
-        stdout_thread = threading.Thread(target=self._read_stdout)
-        stdout_thread.daemon = True
-        stdout_thread.start()
-        
-        time.sleep(1)  # Give server time to start
-        
-    def _read_stderr(self):
-        """Read stderr output from server"""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                line = self.server_process.stderr.readline()
-                if line:
-                    print(f"SERVER STDERR: {line.decode().strip()}")
-            except:
-                break
-                
-    def _read_stdout(self):
-        """Read stdout output from server without Content-Length parsing"""
-        buffer = b""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                data = self.server_process.stdout.readline()
-                if not data:
-                    break
-                buffer += data
-                
-                # Try to parse JSON directly from each line
-                try:
-                    message = buffer.strip()
-                    if message:
-                        parsed = json.loads(message.decode())
-                        self.message_queue.put(parsed)
-                        print(f"SERVER MESSAGE: {json.dumps(parsed, indent=2)}")
-                        buffer = b""
-                except json.JSONDecodeError:
-                    # If not valid JSON yet, continue reading
-                    continue
-            except:
-                break
-                        
-    def send_jsonrpc_request(self, method, params=None, id=1):
-        """Send a JSON-RPC request without Content-Length header"""
-        request = {
-            "jsonrpc": "2.0",
-            "method": method,
-            "id": id,
-            "params": {}
-        }
-        if params:
-            request["params"] = params
-            
-        request_str = json.dumps(request)
-        message = f"{request_str}\n"
-        print(f"SENDING: {repr(message)}")
-        
-        self.server_process.stdin.write(message.encode())
-        self.server_process.stdin.flush()
-        
-        # Wait for response with timeout
-        try:
-            response = self.message_queue.get(timeout=5)
-            return response
-        except queue.Empty:
-            print("TIMEOUT: No response received")
-            return None
-            
-    def test_initialize(self):
-        """Test initialize request"""
-        print("\n=== Testing Initialize ===")
-        
-        params = {
-            "protocolVersion": "2025-11-25",
-            "capabilities": {},
-            "clientInfo": {
-                "name": "test-client",
-                "version": "1.0.0"
-            }
-        }
-        
-        print("\nSending initialize request...")
-        init_response = self.send_jsonrpc_request("initialize", params, id=1)
-        if init_response:
-            print(f"Initialize response: {json.dumps(init_response, indent=2)}")
-            print("✓ Initialize successful")
-            return True
-        else:
-            print("✗ Initialize failed")
-            return False
-            
-    def test_simple_ping(self):
-        """Test simple ping"""
-        print("\n=== Testing Simple Ping ===")
-        
-        # Try a ping
-        print("\nSending ping request...")
-        ping_response = self.send_jsonrpc_request("ping", id=2)
-        if ping_response:
-            print(f"Ping response: {json.dumps(ping_response, indent=2)}")
-            print("✓ Ping successful")
-            return True
-        else:
-            print("✗ Ping failed")
-            return False
-        
-    def stop_server(self):
-        """Stop MCP server process"""
-        if self.server_process:
-            print("\nStopping server...")
-            self.server_process.terminate()
-            try:
-                self.server_process.wait(timeout=5)
-            except subprocess.TimeoutExpired:
-                self.server_process.kill()
-            self.server_process = None
-
-def main():
-    if len(sys.argv) != 2:
-        print("Usage: python3 test_content_length.py <server-executable>")
-        sys.exit(1)
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        sys.exit(1)
-        
-    tester = MCPServerTester(server_path)
-    
-    try:
-        tester.start_server()
-        
-        # Wait a bit for server to fully start
-        time.sleep(2)
-        
-        # Test initialize first
-        init_success = tester.test_initialize()
-        
-        if init_success:
-            # Test simple ping
-            ping_success = tester.test_simple_ping()
-            
-            if ping_success:
-                print("\n✓ Server test completed successfully")
-            else:
-                print("\n✗ Ping test failed")
-        else:
-            print("\n✗ Initialize test failed")
-            
-    except KeyboardInterrupt:
-        print("\nTest interrupted by user")
-    except Exception as e:
-        print(f"\nError during test: {e}")
-        import traceback
-        traceback.print_exc()
-    finally:
-        tester.stop_server()
-
-if __name__ == "__main__":
-    main()

+ 0 - 213
test_converters.py

@@ -1,213 +0,0 @@
-#!/usr/bin/env python3
-"""
-Test the converters implemented in compat.vala
-"""
-
-import subprocess
-import json
-import sys
-import os
-
-def test_inject_content_length():
-    """Test the InjectContentLength converter"""
-    print("=== Testing InjectContentLength Converter ===")
-    
-    # Create a simple test program in Vala that uses the converter
-    test_code = """
-using GLib;
-using Mcp.Core.Compat;
-
-public class TestInjectContentLength {
-    public static int main (string[] args) {
-        // Create the converter
-        var converter = new InjectContentLength ();
-        
-        // Test input: JSON message without Content-Length header
-        string input = "{\\"jsonrpc\\": \\"2.0\\", \\"method\\": \\"ping\\", \\"id\\": 1}\\n";
-        
-        // Output buffer
-        uint8[] output = new uint8[1024];
-        size_t bytes_read, bytes_written;
-        
-        // Convert
-        var result = converter.convert (input.data, output, ConverterFlags.NONE, 
-                                       out bytes_read, out bytes_written);
-        
-        // Extract the output
-        string output_str = (string)output;
-        output_str = output_str.substring (0, (int)bytes_written);
-        
-        // Print the result
-        print ("Input: %s", input);
-        print ("Output: %s", output_str);
-        
-        // Check if Content-Length header was added
-        if (output_str.has_prefix ("Content-Length:")) {
-            print ("✓ Content-Length header injected successfully\\n");
-            return 0;
-        } else {
-            print ("✗ Content-Length header not found\\n");
-            return 1;
-        }
-    }
-}
-"""
-    
-    # Write the test code to a file
-    with open("test_inject.vala", "w") as f:
-        f.write(test_code)
-    
-    # Compile and run the test
-    try:
-        # Compile
-        compile_cmd = [
-            "valac",
-            "--pkg", "glib-2.0",
-            "--pkg", "gio-2.0",
-            "--pkg", "json-glib-1.0",
-            "--pkg", "jsonrpc-glib-1.0",
-            "--pkg", "gee-0.8",
-            "--pkg", "posix",
-            "--vapidir", "builddir/src",
-            "--pkg", "mcp-vala",
-            "test_inject.vala",
-            "-o", "test_inject"
-        ]
-        
-        result = subprocess.run(compile_cmd, capture_output=True, text=True, cwd=".")
-        
-        if result.returncode != 0:
-            print(f"Compilation failed: {result.stderr}")
-            print(f"Compilation stdout: {result.stdout}")
-            return False
-            
-        # Run
-        run_result = subprocess.run(["./test_inject"], capture_output=True, text=True)
-        print(run_result.stdout)
-        
-        if run_result.returncode == 0:
-            return True
-        else:
-            print(f"Test failed: {run_result.stderr}")
-            return False
-            
-    except Exception as e:
-        print(f"Error running test: {e}")
-        return False
-    finally:
-        # Clean up
-        for f in ["test_inject.vala", "test_inject"]:
-            try:
-                os.remove(f)
-            except:
-                pass
-
-def test_strip_content_length():
-    """Test the StripContentLength converter"""
-    print("=== Testing StripContentLength Converter ===")
-    
-    # Create a simple test program in Vala that uses the converter
-    test_code = """
-using GLib;
-using Mcp.Core.Compat;
-
-public class TestStripContentLength {
-    public static int main (string[] args) {
-        // Create the converter
-        var converter = new StripContentLength ();
-        
-        // Test input: JSON message with Content-Length header
-        string input = "Content-Length: 45\\r\\n\\r\\n{\\"jsonrpc\\": \\"2.0\\", \\"method\\": \\"ping\\", \\"id\\": 1}";
-        
-        // Output buffer
-        uint8[] output = new uint8[1024];
-        size_t bytes_read, bytes_written;
-        
-        // Convert
-        var result = converter.convert (input.data, output, ConverterFlags.NONE, 
-                                       out bytes_read, out bytes_written);
-        
-        // Extract the output
-        string output_str = (string)output;
-        output_str = output_str.substring (0, (int)bytes_written);
-        
-        // Print the result
-        print ("Input: %s", input);
-        print ("Output: %s", output_str);
-        
-        // Check if Content-Length header was removed and newline was added
-        if (!output_str.has_prefix ("Content-Length:") && output_str.has_suffix ("\\n")) {
-            print ("✓ Content-Length header stripped and newline added successfully\\n");
-            return 0;
-        } else {
-            print ("✗ Content-Length header not stripped or newline not added\\n");
-            return 1;
-        }
-    }
-}
-"""
-    
-    # Write the test code to a file
-    with open("test_strip.vala", "w") as f:
-        f.write(test_code)
-    
-    # Compile and run the test
-    try:
-        # Compile
-        compile_cmd = [
-            "valac",
-            "--pkg", "glib-2.0",
-            "--pkg", "gio-2.0",
-            "--pkg", "json-glib-1.0",
-            "--pkg", "jsonrpc-glib-1.0",
-            "--pkg", "gee-0.8",
-            "--pkg", "posix",
-            "--vapidir", "builddir/src",
-            "--pkg", "mcp-vala",
-            "test_strip.vala",
-            "-o", "test_strip"
-        ]
-        
-        result = subprocess.run(compile_cmd, capture_output=True, text=True, cwd=".")
-        
-        if result.returncode != 0:
-            print(f"Compilation failed: {result.stderr}")
-            return False
-            
-        # Run
-        run_result = subprocess.run(["./test_strip"], capture_output=True, text=True)
-        print(run_result.stdout)
-        
-        if run_result.returncode == 0:
-            return True
-        else:
-            print(f"Test failed: {run_result.stderr}")
-            return False
-            
-    except Exception as e:
-        print(f"Error running test: {e}")
-        return False
-    finally:
-        # Clean up
-        for f in ["test_strip.vala", "test_strip"]:
-            try:
-                os.remove(f)
-            except:
-                pass
-
-def main():
-    print("Testing MCP Converters\n")
-    
-    # Test both converters
-    inject_success = test_inject_content_length()
-    strip_success = test_strip_content_length()
-    
-    if inject_success and strip_success:
-        print("✓ All converter tests passed!")
-        return 0
-    else:
-        print("✗ Some converter tests failed!")
-        return 1
-
-if __name__ == "__main__":
-    sys.exit(main())

+ 0 - 252
test_functional.py

@@ -1,252 +0,0 @@
-#!/usr/bin/env python3
-"""
-Functional testing of MCP server core components
-"""
-
-import subprocess
-import time
-import json
-import sys
-import os
-import threading
-import queue
-
-class MCPServerTester:
-    def __init__(self, server_path):
-        self.server_path = server_path
-        self.server_process = None
-        self.message_queue = queue.Queue()
-        
-    def start_server(self):
-        """Start MCP server process"""
-        print(f"Starting MCP server: {self.server_path}")
-        self.server_process = subprocess.Popen(
-            [self.server_path],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            text=False,
-            bufsize=0
-        )
-        
-        # Start thread to read stderr
-        stderr_thread = threading.Thread(target=self._read_stderr)
-        stderr_thread.daemon = True
-        stderr_thread.start()
-        
-        # Start thread to read stdout
-        stdout_thread = threading.Thread(target=self._read_stdout)
-        stdout_thread.daemon = True
-        stdout_thread.start()
-        
-        time.sleep(1)
-        
-    def _read_stderr(self):
-        """Read stderr output from server"""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                line = self.server_process.stderr.readline()
-                if line:
-                    print(f"SERVER STDERR: {line.decode().strip()}")
-            except:
-                break
-                
-    def _read_stdout(self):
-        """Read stdout output from server without Content-Length parsing"""
-        buffer = b""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                data = self.server_process.stdout.readline()
-                if not data:
-                    break
-                buffer += data
-                
-                # Try to parse JSON directly from each line
-                try:
-                    message = buffer.strip()
-                    if message:
-                        parsed = json.loads(message.decode())
-                        self.message_queue.put(parsed)
-                        buffer = b""
-                except json.JSONDecodeError:
-                    # If not valid JSON yet, continue reading
-                    continue
-            except:
-                break
-                        
-    def send_jsonrpc_request(self, method, params=None, id=1):
-        """Send a JSON-RPC request without Content-Length header"""
-        request = {
-            "jsonrpc": "2.0",
-            "method": method,
-            "id": id,
-            "params": params or {}
-        }
-            
-        request_str = json.dumps(request)
-        message = f"{request_str}\n"
-        
-        self.server_process.stdin.write(message.encode())
-        self.server_process.stdin.flush()
-        
-        try:
-            response = self.message_queue.get(timeout=10)
-            return response
-        except queue.Empty:
-            print("TIMEOUT: No response received")
-            return None
-            
-    def test_server_initialization(self):
-        """Test server initialization and lifecycle"""
-        print("\n=== Testing Server Initialization ===")
-        
-        # Test initialize request
-        init_params = {
-            "protocolVersion": "2025-11-25",
-            "capabilities": {},
-            "clientInfo": {
-                "name": "test-client",
-                "version": "1.0.0"
-            }
-        }
-        
-        print("\nSending initialize request...")
-        init_response = self.send_jsonrpc_request("initialize", init_params, id=1)
-        
-        if init_response and "result" in init_response:
-            result = init_response["result"]
-            
-            # Check protocol version
-            if result.get("protocolVersion") == "2025-11-25":
-                print("✓ Protocol version correct")
-            else:
-                print("✗ Protocol version incorrect")
-                
-            # Check capabilities
-            if "capabilities" in result:
-                caps = result["capabilities"]
-                if "resources" in caps and "tools" in caps and "prompts" in caps:
-                    print("✓ Capabilities structure correct")
-                else:
-                    print("✗ Capabilities structure incorrect")
-            else:
-                print("✗ Capabilities missing")
-                
-            # Check server info
-            if "serverInfo" in result:
-                info = result["serverInfo"]
-                if "name" in info and "version" in info:
-                    print("✓ Server info correct")
-                else:
-                    print("✗ Server info incorrect")
-            else:
-                print("✗ Server info missing")
-                
-            return True
-        else:
-            print("✗ Initialize response invalid")
-            return False
-            
-    def test_jsonrpc_message_handling(self):
-        """Test JSON-RPC message handling with GLib.Variant"""
-        print("\n=== Testing JSON-RPC Message Handling ===")
-        
-        # Test valid JSON-RPC request
-        print("\nTesting valid JSON-RPC request...")
-        ping_response = self.send_jsonrpc_request("ping", {}, id=2)
-        if ping_response and "result" in ping_response and ping_response.get("id") == 2:
-            print("✓ Valid JSON-RPC request handled correctly")
-        else:
-            print("✗ Valid JSON-RPC request failed")
-            
-        # Test request with complex params
-        print("\nTesting request with complex parameters...")
-        complex_params = {
-            "nested": {
-                "array": [1, 2, 3],
-                "object": {"key": "value"},
-                "boolean": True,
-                "number": 42.5,
-                "null": None
-            }
-        }
-        complex_response = self.send_jsonrpc_request("ping", complex_params, id=3)
-        if complex_response and "result" in complex_response:
-            print("✓ Complex parameters handled correctly")
-        else:
-            print("✗ Complex parameters failed")
-            
-        # Test invalid method
-        print("\nTesting invalid method...")
-        invalid_response = self.send_jsonrpc_request("invalid_method", {}, id=4)
-        if invalid_response and "error" in invalid_response:
-            print("✓ Invalid method handled correctly")
-        else:
-            print("✗ Invalid method not handled properly")
-            
-    def test_error_handling(self):
-        """Test error handling throughout the system"""
-        print("\n=== Testing Error Handling ===")
-        
-        # Test malformed JSON (this would need to be sent at a lower level)
-        print("\nTesting error responses...")
-        
-        # Test missing required parameters
-        print("\nTesting missing required parameters...")
-        # This would depend on specific method implementations
-        
-        # Test invalid parameter types
-        print("\nTesting invalid parameter types...")
-        # This would depend on specific method implementations
-        
-        print("✓ Error handling tests completed")
-        
-    def stop_server(self):
-        """Stop MCP server process"""
-        if self.server_process:
-            print("\nStopping server...")
-            self.server_process.terminate()
-            try:
-                self.server_process.wait(timeout=5)
-            except subprocess.TimeoutExpired:
-                self.server_process.kill()
-            self.server_process = None
-
-def main():
-    if len(sys.argv) != 2:
-        print("Usage: python3 test_functional.py <server-executable>")
-        sys.exit(1)
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        sys.exit(1)
-        
-    tester = MCPServerTester(server_path)
-    
-    try:
-        tester.start_server()
-        time.sleep(2)
-        
-        # Run functional tests
-        init_success = tester.test_server_initialization()
-        
-        if init_success:
-            tester.test_jsonrpc_message_handling()
-            tester.test_error_handling()
-            
-            print("\n✓ All functional tests completed successfully")
-        else:
-            print("\n✗ Functional tests failed - initialization error")
-            
-    except KeyboardInterrupt:
-        print("\nTest interrupted by user")
-    except Exception as e:
-        print(f"\nError during test: {e}")
-        import traceback
-        traceback.print_exc()
-    finally:
-        tester.stop_server()
-
-if __name__ == "__main__":
-    main()

+ 0 - 160
test_mcp_with_headers.py

@@ -1,160 +0,0 @@
-#!/usr/bin/env python3
-"""
-Test MCP server connection with proper Content-Length headers
-"""
-
-import subprocess
-import time
-import json
-import sys
-import os
-import threading
-import queue
-
-class MCPServerTester:
-    def __init__(self, server_path):
-        self.server_path = server_path
-        self.server_process = None
-        self.message_queue = queue.Queue()
-        
-    def start_server(self):
-        """Start MCP server process"""
-        print(f"Starting MCP server: {self.server_path}")
-        self.server_process = subprocess.Popen(
-            [self.server_path],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            text=True,
-            bufsize=0
-        )
-        
-        # Start thread to read stderr
-        stderr_thread = threading.Thread(target=self._read_stderr)
-        stderr_thread.daemon = True
-        stderr_thread.start()
-        
-        # Start thread to read stdout
-        stdout_thread = threading.Thread(target=self._read_stdout)
-        stdout_thread.daemon = True
-        stdout_thread.start()
-        
-        time.sleep(1)  # Give server time to start
-        
-    def _read_stderr(self):
-        """Read stderr output from server"""
-        while self.server_process and self.server_process.poll() is None:
-            line = self.server_process.stderr.readline()
-            if line:
-                print(f"SERVER STDERR: {line.strip()}")
-                
-    def _read_stdout(self):
-        """Read stdout output from server without Content-Length parsing"""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                line = self.server_process.stdout.readline()
-                if not line:
-                    break
-                
-                # Try to parse JSON directly from each line
-                try:
-                    message = line.strip()
-                    if message:
-                        parsed = json.loads(message)
-                        self.message_queue.put(parsed)
-                        print(f"SERVER MESSAGE: {json.dumps(parsed, indent=2)}")
-                except json.JSONDecodeError:
-                    # If not valid JSON yet, continue reading
-                    continue
-            except:
-                break
-                        
-    def send_jsonrpc_request(self, method, params=None, id=1):
-        """Send a JSON-RPC request without Content-Length header"""
-        request = {
-            "jsonrpc": "2.0",
-            "method": method,
-            "id": id,
-            "params": {}
-        }
-        if params:
-            request["params"] = params
-            
-        request_str = json.dumps(request)
-        message = f"{request_str}\n"
-        print(f"SENDING: {repr(message)}")
-        
-        self.server_process.stdin.write(message)
-        self.server_process.stdin.flush()
-        
-        # Wait for response with timeout
-        try:
-            response = self.message_queue.get(timeout=5)
-            return response
-        except queue.Empty:
-            print("TIMEOUT: No response received")
-            return None
-            
-    def test_simple_ping(self):
-        """Test simple ping"""
-        print("\n=== Testing Simple Ping ===")
-        
-        # Try a ping
-        print("\nSending ping request...")
-        ping_response = self.send_jsonrpc_request("ping", id=1)
-        if ping_response:
-            print(f"Ping response: {json.dumps(ping_response, indent=2)}")
-            print("✓ Ping successful")
-            return True
-        else:
-            print("✗ Ping failed")
-            return False
-        
-    def stop_server(self):
-        """Stop MCP server process"""
-        if self.server_process:
-            print("\nStopping server...")
-            self.server_process.terminate()
-            try:
-                self.server_process.wait(timeout=5)
-            except subprocess.TimeoutExpired:
-                self.server_process.kill()
-            self.server_process = None
-
-def main():
-    if len(sys.argv) != 2:
-        print("Usage: python3 test_mcp_with_headers.py <server-executable>")
-        sys.exit(1)
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        sys.exit(1)
-        
-    tester = MCPServerTester(server_path)
-    
-    try:
-        tester.start_server()
-        
-        # Wait a bit for server to fully start
-        time.sleep(2)
-        
-        # Test simple ping
-        success = tester.test_simple_ping()
-        
-        if success:
-            print("\n✓ Server test completed successfully")
-        else:
-            print("\n✗ Server test failed")
-            
-    except KeyboardInterrupt:
-        print("\nTest interrupted by user")
-    except Exception as e:
-        print(f"\nError during test: {e}")
-        import traceback
-        traceback.print_exc()
-    finally:
-        tester.stop_server()
-
-if __name__ == "__main__":
-    main()

+ 0 - 272
test_message_sizes.py

@@ -1,272 +0,0 @@
-#!/usr/bin/env python3
-"""
-Test MCP server with various message sizes and edge cases
-"""
-
-import subprocess
-import time
-import json
-import sys
-import os
-import threading
-import queue
-
-class MCPServerTester:
-    def __init__(self, server_path):
-        self.server_path = server_path
-        self.server_process = None
-        self.message_queue = queue.Queue()
-        
-    def start_server(self):
-        """Start MCP server process"""
-        print(f"Starting MCP server: {self.server_path}")
-        self.server_process = subprocess.Popen(
-            [self.server_path],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            text=False,
-            bufsize=0
-        )
-        
-        # Start thread to read stderr
-        stderr_thread = threading.Thread(target=self._read_stderr)
-        stderr_thread.daemon = True
-        stderr_thread.start()
-        
-        # Start thread to read stdout
-        stdout_thread = threading.Thread(target=self._read_stdout)
-        stdout_thread.daemon = True
-        stdout_thread.start()
-        
-        time.sleep(1)
-        
-    def _read_stderr(self):
-        """Read stderr output from server"""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                line = self.server_process.stderr.readline()
-                if line:
-                    print(f"SERVER STDERR: {line.decode().strip()}")
-            except:
-                break
-                
-    def _read_stdout(self):
-        """Read stdout output from server without Content-Length parsing"""
-        buffer = b""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                data = self.server_process.stdout.readline()
-                if not data:
-                    break
-                buffer += data
-                
-                # Try to parse JSON directly from each line
-                try:
-                    message = buffer.strip()
-                    if message:
-                        parsed = json.loads(message.decode())
-                        self.message_queue.put(parsed)
-                        buffer = b""
-                except json.JSONDecodeError:
-                    # If not valid JSON yet, continue reading
-                    continue
-            except:
-                break
-                        
-    def send_jsonrpc_request(self, method, params=None, id=1):
-        """Send a JSON-RPC request without Content-Length header"""
-        request = {
-            "jsonrpc": "2.0",
-            "method": method,
-            "id": id,
-            "params": params or {}
-        }
-            
-        request_str = json.dumps(request)
-        message = f"{request_str}\n"
-        
-        self.server_process.stdin.write(message.encode())
-        self.server_process.stdin.flush()
-        
-        try:
-            response = self.message_queue.get(timeout=10)
-            return response
-        except queue.Empty:
-            print("TIMEOUT: No response received")
-            return None
-            
-    def test_message_sizes(self):
-        """Test various message sizes"""
-        print("\n=== Testing Various Message Sizes ===")
-        
-        # Test small message
-        print("\nTesting small message...")
-        small_response = self.send_jsonrpc_request("ping", id=1)
-        if small_response:
-            print("✓ Small message successful")
-        else:
-            print("✗ Small message failed")
-            
-        # Test medium message
-        print("\nTesting medium message...")
-        medium_params = {
-            "data": "x" * 1000,  # 1KB of data
-            "metadata": {
-                "timestamp": "2025-12-12T03:29:00Z",
-                "source": "test-client",
-                "version": "1.0.0"
-            }
-        }
-        medium_response = self.send_jsonrpc_request("ping", medium_params, id=2)
-        if medium_response:
-            print("✓ Medium message successful")
-        else:
-            print("✗ Medium message failed")
-            
-        # Test large message
-        print("\nTesting large message...")
-        large_params = {
-            "data": "x" * 10000,  # 10KB of data
-            "metadata": {
-                "timestamp": "2025-12-12T03:29:00Z",
-                "source": "test-client",
-                "version": "1.0.0",
-                "extra": "y" * 5000
-            }
-        }
-        large_response = self.send_jsonrpc_request("ping", large_params, id=3)
-        if large_response:
-            print("✓ Large message successful")
-        else:
-            print("✗ Large message failed")
-            
-        # Test very large message
-        print("\nTesting very large message...")
-        very_large_params = {
-            "data": "x" * 50000,  # 50KB of data
-            "metadata": {
-                "timestamp": "2025-12-12T03:29:00Z",
-                "source": "test-client",
-                "version": "1.0.0",
-                "extra": "y" * 25000
-            }
-        }
-        very_large_response = self.send_jsonrpc_request("ping", very_large_params, id=4)
-        if very_large_response:
-            print("✓ Very large message successful")
-        else:
-            print("✗ Very large message failed")
-            
-    def test_edge_cases(self):
-        """Test edge cases"""
-        print("\n=== Testing Edge Cases ===")
-        
-        # Test empty params
-        print("\nTesting empty params...")
-        empty_response = self.send_jsonrpc_request("ping", {}, id=5)
-        if empty_response:
-            print("✓ Empty params successful")
-        else:
-            print("✗ Empty params failed")
-            
-        # Test null params
-        print("\nTesting null params...")
-        null_response = self.send_jsonrpc_request("ping", None, id=6)
-        if null_response:
-            print("✓ Null params successful")
-        else:
-            print("✗ Null params failed")
-            
-        # Test special characters
-        print("\nTesting special characters...")
-        special_params = {
-            "data": "Special chars: \n\t\r\"'\\",
-            "unicode": "Unicode: ñáéíóú 中文 🚀",
-            "emoji": "🎉👍💻🔧"
-        }
-        special_response = self.send_jsonrpc_request("ping", special_params, id=7)
-        if special_response:
-            print("✓ Special characters successful")
-        else:
-            print("✗ Special characters failed")
-            
-    def test_concurrent_requests(self):
-        """Test concurrent requests"""
-        print("\n=== Testing Concurrent Requests ===")
-        
-        def send_request(request_id):
-            params = {"request_id": request_id, "data": f"concurrent_{request_id}"}
-            return self.send_jsonrpc_request("ping", params, request_id)
-        
-        # Send multiple requests quickly
-        print("\nSending 10 concurrent requests...")
-        responses = []
-        for i in range(10):
-            response = send_request(10 + i)
-            responses.append(response)
-            
-        successful = sum(1 for r in responses if r is not None)
-        print(f"✓ {successful}/10 concurrent requests successful")
-        
-    def stop_server(self):
-        """Stop MCP server process"""
-        if self.server_process:
-            print("\nStopping server...")
-            self.server_process.terminate()
-            try:
-                self.server_process.wait(timeout=5)
-            except subprocess.TimeoutExpired:
-                self.server_process.kill()
-            self.server_process = None
-
-def main():
-    if len(sys.argv) != 2:
-        print("Usage: python3 test_message_sizes.py <server-executable>")
-        sys.exit(1)
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        sys.exit(1)
-        
-    tester = MCPServerTester(server_path)
-    
-    try:
-        tester.start_server()
-        time.sleep(2)
-        
-        # Initialize first
-        init_params = {
-            "protocolVersion": "2025-11-25",
-            "capabilities": {},
-            "clientInfo": {
-                "name": "test-client",
-                "version": "1.0.0"
-            }
-        }
-        init_response = tester.send_jsonrpc_request("initialize", init_params, id=0)
-        
-        if init_response:
-            print("✓ Server initialized successfully")
-            
-            # Run tests
-            tester.test_message_sizes()
-            tester.test_edge_cases()
-            tester.test_concurrent_requests()
-            
-            print("\n✓ All message size tests completed successfully")
-        else:
-            print("✗ Failed to initialize server")
-            
-    except KeyboardInterrupt:
-        print("\nTest interrupted by user")
-    except Exception as e:
-        print(f"\nError during test: {e}")
-        import traceback
-        traceback.print_exc()
-    finally:
-        tester.stop_server()
-
-if __name__ == "__main__":
-    main()

+ 0 - 89
test_pagination.py

@@ -1,89 +0,0 @@
-#!/usr/bin/env python3
-"""
-Test script to verify pagination implementation in MCP prompts.
-"""
-
-import json
-import subprocess
-import sys
-import os
-
-def run_test(test_name, input_data, expected_keys):
-    """Run a test case and verify the response."""
-    print(f"Running test: {test_name}")
-    
-    # Create a temporary input file
-    input_file = "test_input.json"
-    with open(input_file, "w") as f:
-        json.dump(input_data, f)
-    
-    try:
-        # Run the server with the test input
-        # Note: This is a simplified test - in a real scenario, we'd need to
-        # set up a proper MCP server connection
-        result = subprocess.run(
-            ["cat", input_file],
-            capture_output=True,
-            text=True
-        )
-        
-        # For now, just verify the input format is correct
-        print(f"  Input: {json.dumps(input_data, indent=2)}")
-        print(f"  Expected keys: {expected_keys}")
-        print(f"  Test passed: Input format is correct")
-        return True
-        
-    except Exception as e:
-        print(f"  Error: {e}")
-        return False
-    finally:
-        # Clean up
-        if os.path.exists(input_file):
-            os.remove(input_file)
-
-def main():
-    """Run pagination tests."""
-    print("Testing MCP Prompts Pagination Implementation")
-    print("=" * 50)
-    
-    # Test 1: Request without cursor (first page)
-    test1_input = {
-        "jsonrpc": "2.0",
-        "id": 1,
-        "method": "prompts/list",
-        "params": {}
-    }
-    run_test("First page request", test1_input, ["prompts"])
-    
-    # Test 2: Request with cursor (subsequent page)
-    test2_input = {
-        "jsonrpc": "2.0",
-        "id": 2,
-        "method": "prompts/list",
-        "params": {
-            "cursor": "1"
-        }
-    }
-    run_test("Second page request", test2_input, ["prompts"])
-    
-    # Test 3: Request with invalid cursor (should default to first page)
-    test3_input = {
-        "jsonrpc": "2.0",
-        "id": 3,
-        "method": "prompts/list",
-        "params": {
-            "cursor": "invalid"
-        }
-    }
-    run_test("Invalid cursor request", test3_input, ["prompts"])
-    
-    print("\n" + "=" * 50)
-    print("All pagination tests completed!")
-    print("\nImplementation Summary:")
-    print("- Added cursor parameter support to prompts/list")
-    print("- Implemented pagination with 10 prompts per page")
-    print("- Added nextCursor field when more prompts are available")
-    print("- Return null for nextCursor when all prompts have been returned")
-
-if __name__ == "__main__":
-    main()

+ 0 - 179
test_prompt_validation.py

@@ -1,179 +0,0 @@
-#!/usr/bin/env python3
-"""
-Test script to reproduce the prompt validation error
-"""
-
-import subprocess
-import json
-import sys
-import os
-
-def test_server_prompt():
-    """Test the MCP server prompt functionality"""
-    if len(sys.argv) != 2:
-        print("Usage: python3 test_prompt_validation.py <server-executable>")
-        sys.exit(1)
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        sys.exit(1)
-    
-    print(f"Testing server: {server_path}")
-    
-    # Start the server process
-    process = subprocess.Popen(
-        [server_path],
-        stdin=subprocess.PIPE,
-        stdout=subprocess.PIPE,
-        stderr=subprocess.PIPE,
-        text=False
-    )
-    
-    try:
-        # Send initialize request
-        init_request = {
-            "jsonrpc": "2.0",
-            "method": "initialize",
-            "id": 0,
-            "params": {
-                "protocolVersion": "2025-11-25",
-                "capabilities": {},
-                "clientInfo": {
-                    "name": "test-client",
-                    "version": "1.0.0"
-                }
-            }
-        }
-        
-        request_str = json.dumps(init_request)
-        message = f"Content-Length: {len(request_str)}\r\n\r\n{request_str}"
-        process.stdin.write(message.encode())
-        process.stdin.flush()
-        
-        # Read response
-        response_line = process.stdout.readline()
-        if response_line.startswith(b"Content-Length:"):
-            content_length = int(response_line.decode().split(":")[1].strip())
-            process.stdout.readline()  # Empty line
-            response_data = process.stdout.read(content_length)
-            response = json.loads(response_data.decode())
-            
-            if "result" in response:
-                print("✓ Server initialized successfully")
-            else:
-                print("✗ Failed to initialize server")
-                print(f"Response: {response}")
-                return False
-        
-        # List prompts
-        list_request = {
-            "jsonrpc": "2.0",
-            "method": "prompts/list",
-            "id": 1,
-            "params": {}
-        }
-        
-        request_str = json.dumps(list_request)
-        message = f"Content-Length: {len(request_str)}\r\n\r\n{request_str}"
-        process.stdin.write(message.encode())
-        process.stdin.flush()
-        
-        # Read response
-        response_line = process.stdout.readline()
-        if response_line.startswith(b"Content-Length:"):
-            content_length = int(response_line.decode().split(":")[1].strip())
-            process.stdout.readline()  # Empty line
-            response_data = process.stdout.read(content_length)
-            response = json.loads(response_data.decode())
-            
-            if "result" in response and "prompts" in response["result"]:
-                prompts = response["result"]["prompts"]
-                print(f"✓ Found {len(prompts)} prompts")
-                
-                if prompts:
-                    # Get the first prompt
-                    prompt_name = prompts[0]["name"]
-                    print(f"Getting prompt: {prompt_name}")
-                    
-                    get_request = {
-                        "jsonrpc": "2.0",
-                        "method": "prompts/get",
-                        "id": 2,
-                        "params": {
-                            "name": prompt_name
-                        }
-                    }
-                    
-                    request_str = json.dumps(get_request)
-                    message = f"Content-Length: {len(request_str)}\r\n\r\n{request_str}"
-                    process.stdin.write(message.encode())
-                    process.stdin.flush()
-                    
-                    # Read response
-                    response_line = process.stdout.readline()
-                    if response_line.startswith(b"Content-Length:"):
-                        content_length = int(response_line.decode().split(":")[1].strip())
-                        process.stdout.readline()  # Empty line
-                        response_data = process.stdout.read(content_length)
-                        response = json.loads(response_data.decode())
-                        
-                        if "result" in response:
-                            print("✓ Prompt retrieved successfully")
-                            result = response["result"]
-                            
-                            # Validate the structure
-                            if "messages" in result:
-                                messages = result["messages"]
-                                print(f"✓ Found {len(messages)} messages")
-                                
-                                for i, message in enumerate(messages):
-                                    print(f"\nMessage {i}:")
-                                    print(f"  Role: {message.get('role')}")
-                                    
-                                    if "content" in message:
-                                        content = message["content"]
-                                        content_type = content.get("type")
-                                        print(f"  Content type: {content_type}")
-                                        print(f"  Content: {json.dumps(content, indent=2)}")
-                                        
-                                        # Check for validation issues
-                                        if content_type == "text":
-                                            if "text" not in content:
-                                                print("  ✗ Missing 'text' field for text content")
-                                        elif content_type in ["image", "audio"]:
-                                            if "data" not in content:
-                                                print(f"  ✗ Missing 'data' field for {content_type} content")
-                                            if "mimeType" not in content:
-                                                print(f"  ✗ Missing 'mimeType' field for {content_type} content")
-                                        elif content_type == "resource_link":
-                                            if "name" not in content:
-                                                print("  ✗ Missing 'name' field for resource_link content")
-                                            if "uri" not in content:
-                                                print("  ✗ Missing 'uri' field for resource_link content")
-                                        elif content_type == "resource":
-                                            if "resource" not in content:
-                                                print("  ✗ Missing 'resource' field for resource content")
-                            else:
-                                print("✗ No 'messages' field in response")
-                        else:
-                            print("✗ No 'result' field in response")
-                            if "error" in response:
-                                print(f"ERROR: {json.dumps(response['error'], indent=2)}")
-                                return False
-                else:
-                    print("✗ No prompts found")
-            else:
-                print("✗ Failed to list prompts")
-                print(f"Response: {response}")
-                return False
-        
-        return True
-        
-    finally:
-        process.terminate()
-        process.wait()
-
-if __name__ == "__main__":
-    success = test_server_prompt()
-    sys.exit(0 if success else 1)

+ 0 - 343
test_resources.py

@@ -1,343 +0,0 @@
-#!/usr/bin/env python3
-"""
-Resource handling testing for MCP server
-"""
-
-import subprocess
-import time
-import json
-import sys
-import os
-import threading
-import queue
-import tempfile
-import shutil
-
-class MCPServerTester:
-    def __init__(self, server_path):
-        self.server_path = server_path
-        self.server_process = None
-        self.message_queue = queue.Queue()
-        self.test_dir = None
-        
-    def start_server(self):
-        """Start MCP server process"""
-        # Create a temporary directory for testing
-        self.test_dir = tempfile.mkdtemp(prefix="mcp_test_")
-        
-        # Create some test files
-        with open(os.path.join(self.test_dir, "test.txt"), "w") as f:
-            f.write("Hello, World!")
-        with open(os.path.join(self.test_dir, "test.json"), "w") as f:
-            json.dump({"message": "test", "value": 42}, f)
-        with open(os.path.join(self.test_dir, "binary.dat"), "wb") as f:
-            f.write(b"\x00\x01\x02\x03\x04\x05")
-            
-        print(f"Starting MCP server: {self.server_path} with test directory: {self.test_dir}")
-        self.server_process = subprocess.Popen(
-            [self.server_path, self.test_dir],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            text=False,
-            bufsize=0
-        )
-        
-        # Start thread to read stderr
-        stderr_thread = threading.Thread(target=self._read_stderr)
-        stderr_thread.daemon = True
-        stderr_thread.start()
-        
-        # Start thread to read stdout
-        stdout_thread = threading.Thread(target=self._read_stdout)
-        stdout_thread.daemon = True
-        stdout_thread.start()
-        
-        time.sleep(1)
-        
-    def _read_stderr(self):
-        """Read stderr output from server"""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                line = self.server_process.stderr.readline()
-                if line:
-                    print(f"SERVER STDERR: {line.decode().strip()}")
-            except:
-                break
-                
-    def _read_stdout(self):
-        """Read stdout output from server without Content-Length parsing"""
-        buffer = b""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                data = self.server_process.stdout.readline()
-                if not data:
-                    break
-                buffer += data
-                
-                # Try to parse JSON directly from each line
-                try:
-                    message = buffer.strip()
-                    if message:
-                        parsed = json.loads(message.decode())
-                        self.message_queue.put(parsed)
-                        buffer = b""
-                except json.JSONDecodeError:
-                    # If not valid JSON yet, continue reading
-                    continue
-            except:
-                break
-                        
-    def send_jsonrpc_request(self, method, params=None, id=1):
-        """Send a JSON-RPC request without Content-Length header"""
-        request = {
-            "jsonrpc": "2.0",
-            "method": method,
-            "id": id,
-            "params": params or {}
-        }
-            
-        request_str = json.dumps(request)
-        message = f"{request_str}\n"
-        
-        self.server_process.stdin.write(message.encode())
-        self.server_process.stdin.flush()
-        
-        try:
-            response = self.message_queue.get(timeout=10)
-            return response
-        except queue.Empty:
-            print("TIMEOUT: No response received")
-            return None
-            
-    def test_resource_registration_and_discovery(self):
-        """Test resource registration and discovery"""
-        print("\n=== Testing Resource Registration and Discovery ===")
-        
-        # Test resources/list
-        print("\nTesting resources/list...")
-        list_response = self.send_jsonrpc_request("resources/list", id=1)
-        
-        if list_response and "result" in list_response:
-            result = list_response["result"]
-            if "resources" in result:
-                resources = result["resources"]
-                print(f"✓ Found {len(resources)} resources")
-                
-                # Check if our test files are listed
-                resource_uris = [r.get("uri", "") for r in resources]
-                test_files = ["test.txt", "test.json", "binary.dat"]
-                
-                for filename in test_files:
-                    found = any(filename in uri for uri in resource_uris)
-                    if found:
-                        print(f"✓ Found {filename} in resource list")
-                    else:
-                        print(f"✗ Missing {filename} in resource list")
-                        
-                return True
-            else:
-                print("✗ No resources field in response")
-                return False
-        else:
-            print("✗ Failed to list resources")
-            return False
-            
-    def test_resource_content_retrieval(self):
-        """Test resource content retrieval"""
-        print("\n=== Testing Resource Content Retrieval ===")
-        
-        # Test reading text file
-        print("\nTesting text file read...")
-        txt_uri = f"file://{os.path.join(self.test_dir, 'test.txt')}"
-        txt_response = self.send_jsonrpc_request("resources/read", {"uri": txt_uri}, id=2)
-        
-        if txt_response and "result" in txt_response:
-            result = txt_response["result"]
-            if "contents" in result and len(result["contents"]) > 0:
-                content = result["contents"][0]
-                if content.get("text") == "Hello, World!":
-                    print("✓ Text file content correct")
-                else:
-                    print(f"✗ Text file content incorrect: {content.get('text')}")
-            else:
-                print("✗ No content in text file response")
-        else:
-            print("✗ Failed to read text file")
-            
-        # Test reading JSON file
-        print("\nTesting JSON file read...")
-        json_uri = f"file://{os.path.join(self.test_dir, 'test.json')}"
-        json_response = self.send_jsonrpc_request("resources/read", {"uri": json_uri}, id=3)
-        
-        if json_response and "result" in json_response:
-            result = json_response["result"]
-            if "contents" in result and len(result["contents"]) > 0:
-                content = result["contents"][0]
-                try:
-                    json_data = json.loads(content.get("text", "{}"))
-                    if json_data.get("message") == "test" and json_data.get("value") == 42:
-                        print("✓ JSON file content correct")
-                    else:
-                        print(f"✗ JSON file content incorrect: {json_data}")
-                except json.JSONDecodeError:
-                    print("✗ JSON file content is not valid JSON")
-            else:
-                print("✗ No content in JSON file response")
-        else:
-            print("✗ Failed to read JSON file")
-            
-        # Test reading binary file
-        print("\nTesting binary file read...")
-        bin_uri = f"file://{os.path.join(self.test_dir, 'binary.dat')}"
-        bin_response = self.send_jsonrpc_request("resources/read", {"uri": bin_uri}, id=4)
-        
-        if bin_response and "result" in bin_response:
-            result = bin_response["result"]
-            if "contents" in result and len(result["contents"]) > 0:
-                content = result["contents"][0]
-                if "blob" in content:
-                    print("✓ Binary file read as blob")
-                else:
-                    print("✗ Binary file not read as blob")
-            else:
-                print("✗ No content in binary file response")
-        else:
-            print("✗ Failed to read binary file")
-            
-    def test_resource_subscription_and_notifications(self):
-        """Test resource subscription and notifications"""
-        print("\n=== Testing Resource Subscription and Notifications ===")
-        
-        # Test subscription
-        print("\nTesting resource subscription...")
-        txt_uri = f"file://{os.path.join(self.test_dir, 'test.txt')}"
-        sub_response = self.send_jsonrpc_request("resources/subscribe", {"uri": txt_uri}, id=5)
-        
-        if sub_response and "result" in sub_response:
-            print("✓ Resource subscription successful")
-            
-            # Test unsubscription
-            print("\nTesting resource unsubscription...")
-            unsub_response = self.send_jsonrpc_request("resources/unsubscribe", {"uri": txt_uri}, id=6)
-            
-            if unsub_response and "result" in unsub_response:
-                print("✓ Resource unsubscription successful")
-            else:
-                print("✗ Resource unsubscription failed")
-        else:
-            print("✗ Resource subscription failed")
-            
-    def test_resource_templates(self):
-        """Test resource template functionality"""
-        print("\n=== Testing Resource Templates ===")
-        
-        # Test templates/list
-        print("\nTesting resources/templates/list...")
-        templates_response = self.send_jsonrpc_request("resources/templates/list", id=7)
-        
-        if templates_response and "result" in templates_response:
-            result = templates_response["result"]
-            if "templates" in result:
-                templates = result["templates"]
-                print(f"✓ Found {len(templates)} templates")
-                return True
-            else:
-                print("✗ No templates field in response")
-                return False
-        else:
-            print("✗ Failed to list templates")
-            return False
-            
-    def test_error_handling(self):
-        """Test error handling for resources"""
-        print("\n=== Testing Resource Error Handling ===")
-        
-        # Test reading non-existent file
-        print("\nTesting non-existent file...")
-        fake_uri = "file:///non/existent/file.txt"
-        error_response = self.send_jsonrpc_request("resources/read", {"uri": fake_uri}, id=8)
-        
-        if error_response and "error" in error_response:
-            print("✓ Non-existent file handled correctly")
-        else:
-            print("✗ Non-existent file not handled properly")
-            
-        # Test missing URI parameter
-        print("\nTesting missing URI parameter...")
-        missing_response = self.send_jsonrpc_request("resources/read", {}, id=9)
-        
-        if missing_response and "error" in missing_response:
-            print("✓ Missing URI parameter handled correctly")
-        else:
-            print("✗ Missing URI parameter not handled properly")
-            
-    def cleanup(self):
-        """Clean up test environment"""
-        if self.test_dir and os.path.exists(self.test_dir):
-            shutil.rmtree(self.test_dir)
-            
-    def stop_server(self):
-        """Stop MCP server process"""
-        if self.server_process:
-            print("\nStopping server...")
-            self.server_process.terminate()
-            try:
-                self.server_process.wait(timeout=5)
-            except subprocess.TimeoutExpired:
-                self.server_process.kill()
-            self.server_process = None
-
-def main():
-    if len(sys.argv) != 2:
-        print("Usage: python3 test_resources.py <server-executable>")
-        sys.exit(1)
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        sys.exit(1)
-        
-    tester = MCPServerTester(server_path)
-    
-    try:
-        tester.start_server()
-        time.sleep(2)
-        
-        # Initialize first
-        init_params = {
-            "protocolVersion": "2025-11-25",
-            "capabilities": {},
-            "clientInfo": {
-                "name": "test-client",
-                "version": "1.0.0"
-            }
-        }
-        init_response = tester.send_jsonrpc_request("initialize", init_params, id=0)
-        
-        if init_response:
-            print("✓ Server initialized successfully")
-            
-            # Run resource tests
-            tester.test_resource_registration_and_discovery()
-            tester.test_resource_content_retrieval()
-            tester.test_resource_subscription_and_notifications()
-            tester.test_resource_templates()
-            tester.test_error_handling()
-            
-            print("\n✓ All resource tests completed successfully")
-        else:
-            print("✗ Failed to initialize server")
-            
-    except KeyboardInterrupt:
-        print("\nTest interrupted by user")
-    except Exception as e:
-        print(f"\nError during test: {e}")
-        import traceback
-        traceback.print_exc()
-    finally:
-        tester.stop_server()
-        tester.cleanup()
-
-if __name__ == "__main__":
-    main()

+ 0 - 361
test_resources_fixed.py

@@ -1,361 +0,0 @@
-#!/usr/bin/env python3
-"""
-Resource handling testing for MCP server - fixed version
-"""
-
-import subprocess
-import time
-import json
-import sys
-import os
-import threading
-import queue
-import tempfile
-import shutil
-
-class MCPServerTester:
-    def __init__(self, server_path):
-        self.server_path = server_path
-        self.server_process = None
-        self.message_queue = queue.Queue()
-        self.test_dir = None
-        
-    def start_server(self):
-        """Start MCP server process"""
-        # Create a temporary directory for testing
-        self.test_dir = tempfile.mkdtemp(prefix="mcp_test_")
-        
-        # Create some test files
-        with open(os.path.join(self.test_dir, "test.txt"), "w") as f:
-            f.write("Hello, World!")
-        with open(os.path.join(self.test_dir, "test.json"), "w") as f:
-            json.dump({"message": "test", "value": 42}, f)
-        with open(os.path.join(self.test_dir, "binary.dat"), "wb") as f:
-            f.write(b"\x00\x01\x02\x03\x04\x05")
-            
-        print(f"Starting MCP server: {self.server_path} with test directory: {self.test_dir}")
-        self.server_process = subprocess.Popen(
-            [self.server_path, self.test_dir],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            text=False,
-            bufsize=0
-        )
-        
-        # Start thread to read stderr
-        stderr_thread = threading.Thread(target=self._read_stderr)
-        stderr_thread.daemon = True
-        stderr_thread.start()
-        
-        # Start thread to read stdout
-        stdout_thread = threading.Thread(target=self._read_stdout)
-        stdout_thread.daemon = True
-        stdout_thread.start()
-        
-        time.sleep(1)
-        
-    def _read_stderr(self):
-        """Read stderr output from server"""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                line = self.server_process.stderr.readline()
-                if line:
-                    print(f"SERVER STDERR: {line.decode().strip()}")
-            except:
-                break
-                
-    def _read_stdout(self):
-        """Read stdout output from server without Content-Length parsing"""
-        buffer = b""
-        while self.server_process and self.server_process.poll() is None:
-            try:
-                data = self.server_process.stdout.readline()
-                if not data:
-                    break
-                buffer += data
-                
-                # Try to parse JSON directly from each line
-                try:
-                    message = buffer.strip()
-                    if message:
-                        parsed = json.loads(message.decode())
-                        self.message_queue.put(parsed)
-                        buffer = b""
-                except json.JSONDecodeError:
-                    # If not valid JSON yet, continue reading
-                    continue
-            except:
-                break
-                        
-    def send_jsonrpc_request(self, method, params=None, id=1):
-        """Send a JSON-RPC request without Content-Length header"""
-        request = {
-            "jsonrpc": "2.0",
-            "method": method,
-            "id": id,
-            "params": params or {}
-        }
-            
-        request_str = json.dumps(request)
-        message = f"{request_str}\n"
-        
-        self.server_process.stdin.write(message.encode())
-        self.server_process.stdin.flush()
-        
-        try:
-            response = self.message_queue.get(timeout=10)
-            return response
-        except queue.Empty:
-            print("TIMEOUT: No response received")
-            return None
-            
-    def test_resource_registration_and_discovery(self):
-        """Test resource registration and discovery"""
-        print("\n=== Testing Resource Registration and Discovery ===")
-        
-        # Test resources/list
-        print("\nTesting resources/list...")
-        list_response = self.send_jsonrpc_request("resources/list", id=1)
-        
-        if list_response and "result" in list_response:
-            result = list_response["result"]
-            if "resources" in result:
-                resources = result["resources"]
-                print(f"✓ Found {len(resources)} resources")
-                
-                # Check if our test files are listed
-                resource_uris = [r.get("uri", "") for r in resources]
-                test_files = ["test.txt", "test.json", "binary.dat"]
-                
-                for filename in test_files:
-                    found = any(filename in uri for uri in resource_uris)
-                    if found:
-                        print(f"✓ Found {filename} in resource list")
-                    else:
-                        print(f"✗ Missing {filename} in resource list")
-                        
-                return True
-            else:
-                print("✗ No resources field in response")
-                return False
-        else:
-            print("✗ Failed to list resources")
-            return False
-            
-    def test_resource_content_retrieval(self):
-        """Test resource content retrieval"""
-        print("\n=== Testing Resource Content Retrieval ===")
-        
-        # Test reading text file
-        print("\nTesting text file read...")
-        txt_uri = f"file://{os.path.join(self.test_dir, 'test.txt')}"
-        txt_response = self.send_jsonrpc_request("resources/read", {"uri": txt_uri}, id=2)
-        
-        if txt_response and "result" in txt_response:
-            result = txt_response["result"]
-            # Handle both response formats
-            if "text" in result:
-                # Direct text format
-                if result["text"] == "Hello, World!":
-                    print("✓ Text file content correct")
-                else:
-                    print(f"✗ Text file content incorrect: {result.get('text')}")
-            elif "contents" in result and len(result["contents"]) > 0:
-                # Contents array format
-                content = result["contents"][0]
-                if content.get("text") == "Hello, World!":
-                    print("✓ Text file content correct")
-                else:
-                    print(f"✗ Text file content incorrect: {content.get('text')}")
-            else:
-                print("✗ No content in text file response")
-        else:
-            print("✗ Failed to read text file")
-            
-        # Test reading JSON file
-        print("\nTesting JSON file read...")
-        json_uri = f"file://{os.path.join(self.test_dir, 'test.json')}"
-        json_response = self.send_jsonrpc_request("resources/read", {"uri": json_uri}, id=3)
-        
-        if json_response and "result" in json_response:
-            result = json_response["result"]
-            if "text" in result:
-                # Direct text format
-                try:
-                    json_data = json.loads(result["text"])
-                    if json_data.get("message") == "test" and json_data.get("value") == 42:
-                        print("✓ JSON file content correct")
-                    else:
-                        print(f"✗ JSON file content incorrect: {json_data}")
-                except json.JSONDecodeError:
-                    print("✗ JSON file content is not valid JSON")
-            elif "contents" in result and len(result["contents"]) > 0:
-                # Contents array format
-                content = result["contents"][0]
-                if content.get("text"):
-                    try:
-                        json_data = json.loads(content.get("text"))
-                        if json_data.get("message") == "test" and json_data.get("value") == 42:
-                            print("✓ JSON file content correct")
-                        else:
-                            print(f"✗ JSON file content incorrect: {json_data}")
-                    except json.JSONDecodeError:
-                        print("✗ JSON file content is not valid JSON")
-                else:
-                    print("✗ JSON file content not in text format")
-            else:
-                print("✗ No content in JSON file response")
-        else:
-            print("✗ Failed to read JSON file")
-            
-        # Test reading binary file
-        print("\nTesting binary file read...")
-        bin_uri = f"file://{os.path.join(self.test_dir, 'binary.dat')}"
-        bin_response = self.send_jsonrpc_request("resources/read", {"uri": bin_uri}, id=4)
-        
-        if bin_response and "result" in bin_response:
-            result = bin_response["result"]
-            if "blob" in result:
-                print("✓ Binary file read as blob")
-            else:
-                print("✗ Binary file not read as blob")
-        else:
-            print("✗ Failed to read binary file")
-            
-    def test_resource_subscription_and_notifications(self):
-        """Test resource subscription and notifications"""
-        print("\n=== Testing Resource Subscription and Notifications ===")
-        
-        # Test subscription
-        print("\nTesting resource subscription...")
-        txt_uri = f"file://{os.path.join(self.test_dir, 'test.txt')}"
-        sub_response = self.send_jsonrpc_request("resources/subscribe", {"uri": txt_uri}, id=5)
-        
-        if sub_response and "result" in sub_response:
-            print("✓ Resource subscription successful")
-            
-            # Test unsubscription
-            print("\nTesting resource unsubscription...")
-            unsub_response = self.send_jsonrpc_request("resources/unsubscribe", {"uri": txt_uri}, id=6)
-            
-            if unsub_response and "result" in unsub_response:
-                print("✓ Resource unsubscription successful")
-            else:
-                print("✗ Resource unsubscription failed")
-        else:
-            print("✗ Resource subscription failed")
-            
-    def test_resource_templates(self):
-        """Test resource template functionality"""
-        print("\n=== Testing Resource Templates ===")
-        
-        # Test templates/list
-        print("\nTesting resources/templates/list...")
-        templates_response = self.send_jsonrpc_request("resources/templates/list", id=7)
-        
-        if templates_response and "result" in templates_response:
-            result = templates_response["result"]
-            if "templates" in result:
-                templates = result["templates"]
-                print(f"✓ Found {len(templates)} templates")
-                return True
-            else:
-                print("✗ No templates field in response")
-                return False
-        else:
-            print("✗ Failed to list templates")
-            return False
-            
-    def test_error_handling(self):
-        """Test error handling for resources"""
-        print("\n=== Testing Resource Error Handling ===")
-        
-        # Test reading non-existent file
-        print("\nTesting non-existent file...")
-        fake_uri = "file:///non/existent/file.txt"
-        error_response = self.send_jsonrpc_request("resources/read", {"uri": fake_uri}, id=8)
-        
-        if error_response and "error" in error_response:
-            print("✓ Non-existent file handled correctly")
-        else:
-            print("✗ Non-existent file not handled properly")
-            
-        # Test missing URI parameter
-        print("\nTesting missing URI parameter...")
-        missing_response = self.send_jsonrpc_request("resources/read", {}, id=9)
-        
-        if missing_response and "error" in missing_response:
-            print("✓ Missing URI parameter handled correctly")
-        else:
-            print("✗ Missing URI parameter not handled properly")
-            
-    def cleanup(self):
-        """Clean up test environment"""
-        if self.test_dir and os.path.exists(self.test_dir):
-            shutil.rmtree(self.test_dir)
-            
-    def stop_server(self):
-        """Stop MCP server process"""
-        if self.server_process:
-            print("\nStopping server...")
-            self.server_process.terminate()
-            try:
-                self.server_process.wait(timeout=5)
-            except subprocess.TimeoutExpired:
-                self.server_process.kill()
-            self.server_process = None
-
-def main():
-    if len(sys.argv) != 2:
-        print("Usage: python3 test_resources_fixed.py <server-executable>")
-        sys.exit(1)
-        
-    server_path = sys.argv[1]
-    if not os.path.exists(server_path):
-        print(f"Error: Server executable '{server_path}' not found")
-        sys.exit(1)
-        
-    tester = MCPServerTester(server_path)
-    
-    try:
-        tester.start_server()
-        time.sleep(2)
-        
-        # Initialize first
-        init_params = {
-            "protocolVersion": "2025-11-25",
-            "capabilities": {},
-            "clientInfo": {
-                "name": "test-client",
-                "version": "1.0.0"
-            }
-        }
-        init_response = tester.send_jsonrpc_request("initialize", init_params, id=0)
-        
-        if init_response:
-            print("✓ Server initialized successfully")
-            
-            # Run resource tests
-            tester.test_resource_registration_and_discovery()
-            tester.test_resource_content_retrieval()
-            tester.test_resource_subscription_and_notifications()
-            tester.test_resource_templates()
-            tester.test_error_handling()
-            
-            print("\n✓ All resource tests completed successfully")
-        else:
-            print("✗ Failed to initialize server")
-            
-    except KeyboardInterrupt:
-        print("\nTest interrupted by user")
-    except Exception as e:
-        print(f"\nError during test: {e}")
-        import traceback
-        traceback.print_exc()
-    finally:
-        tester.stop_server()
-        tester.cleanup()
-
-if __name__ == "__main__":
-    main()

+ 0 - 23
test_with_strace.sh

@@ -1,23 +0,0 @@
-#!/bin/bash
-
-# Test with strace to see what's happening with file descriptors
-echo "Testing with strace..."
-
-strace -e trace=write,read,ioctl -f -o strace.log ./builddir/examples/minimal-server &
-SERVER_PID=$!
-
-# Give it a moment to start
-sleep 0.5
-
-# Send initialize request
-echo '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": {"name": "test-client", "version": "1.0.0"}}}' | nc -N localhost 0 2>/dev/null || echo "nc failed, trying direct pipe"
-
-# Wait a bit
-sleep 1
-
-# Kill the server
-kill $SERVER_PID 2>/dev/null
-
-# Show the strace log
-echo "=== Strace log ==="
-cat strace.log