# 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 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 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 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 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 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 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 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 list_resources (string? cursor) throws Error { var resources = new List (); // 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 (); 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 (); 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