| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028 |
- /*
- * Copyright (C) 2025 Mcp-Vala Project
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Author: Mcp-Vala Project
- */
- using Mcp;
- /**
- * Simple MCP server example.
- *
- * This example demonstrates basic usage of the MCP Vala library
- * with a simple echo tool and basic resource provider.
- */
- public class SimpleServer : GLib.Object {
- private Mcp.Core.Server server;
-
- /**
- * Creates a new SimpleServer.
- */
- public SimpleServer () {
- // Create server info
- var server_info = new Mcp.Types.Protocol.ServerInfo (
- "simple-server",
- "1.0.0"
- );
- server_info.description = "A simple MCP server example";
-
- // Create server capabilities
- var capabilities = new Mcp.Types.Protocol.ServerCapabilities ();
- capabilities.logging = true;
-
- // Create server
- server = new Mcp.Core.Server (server_info, capabilities);
-
- // Register tools with tool manager
- var echo_tool = new EchoTool ();
- try {
- server.tool_manager.register_executor ("echo", echo_tool);
- } catch (Error e) {
- // Error handling
- }
-
- var calculator_tool = new CalculatorTool ();
- try {
- server.tool_manager.register_executor ("calculator", calculator_tool);
- } catch (Error e) {
- // Error handling
- }
-
- var file_tool = new FileOperationTool ();
- try {
- server.tool_manager.register_executor ("file_ops", file_tool);
- } catch (Error e) {
- // Error handling
- }
-
- // Register resource providers with the resource manager
- var file_provider = new FileResourceProvider ();
- server.resource_manager.register_provider ("file", file_provider);
-
- var memory_provider = new MemoryResourceProvider ();
- server.resource_manager.register_provider ("memory", memory_provider);
-
- // Add a resource template
- var template = new Mcp.Resources.Types.Resource.ResourceTemplate (
- "note",
- "Create a new note"
- );
- template.description = "Creates a new text note with specified content";
- server.resource_manager.register_template ("note", template);
-
- // Register prompt templates with the prompt manager
- var code_review_prompt = new CodeReviewPromptTemplate ();
- try {
- server.prompt_manager.register_template ("code_review", code_review_prompt);
- } catch (Error e) {
- // Error handling
- }
-
- var summary_prompt = new SummaryPromptTemplate ();
- try {
- server.prompt_manager.register_template ("summary", summary_prompt);
- } catch (Error e) {
- // Error handling
- }
-
- var explain_prompt = new ExplainPromptTemplate ();
- try {
- server.prompt_manager.register_template ("explain", explain_prompt);
- } catch (Error e) {
- // Error handling
- }
- }
-
- /**
- * Runs the server.
- *
- * @return Exit code
- */
- public async int run () {
- try {
- // Start the server
- bool started = yield server.start ();
- if (!started) {
- return 1;
- }
-
- // Server started. Waiting for connections...
-
- // Start a demo timer to show resource updates
- Timeout.add_seconds (5, () => {
- demo_resource_updates ();
- return true; // Continue timer
- });
-
- // Run the main loop
- var main_loop = new MainLoop ();
-
- // Connect shutdown signal
- server.shutdown.connect (() => {
- main_loop.quit ();
- });
-
- main_loop.run ();
-
- return 0;
- } catch (Error e) {
- return 1;
- }
- }
-
- /**
- * Demonstrates resource updates and notifications.
- */
- private void demo_resource_updates () {
- // Get the memory provider
- // Get the memory provider from the resource manager's providers
- var providers = server.resource_manager.get_providers ();
- MemoryResourceProvider? provider = null;
- foreach (var key in providers.get_keys ()) {
- if (key == "memory") {
- provider = providers.get (key) as MemoryResourceProvider;
- break;
- }
- }
- if (provider != null) {
- // Increment the counter
- int new_value = provider.increment_counter ();
-
- // Create a new note every 30 seconds (6 * 5 second intervals)
- uint note_counter = 0;
- note_counter++;
- if (note_counter % 6 == 0) {
- string uri = provider.create_note (
- "Demo Note %u".printf (note_counter / 6),
- "This is an auto-generated note created at %s".printf (new DateTime.now_utc ().to_string ())
- );
- }
- }
- }
- }
- /**
- * Simple echo tool implementation.
- */
- public class EchoTool : Mcp.Tools.BaseExecutor {
- /**
- * Creates a new EchoTool.
- */
- public EchoTool () {
- // Create tool definition using Variant
- var builder = new VariantBuilder (new VariantType ("a{sv}"));
-
- // Add schema properties
- builder.add ("{sv}", "type", new Variant.string ("object"));
- builder.add ("{sv}", "description", new Variant.string ("Text to echo back"));
-
- var properties_builder = new VariantBuilder (new VariantType ("a{sv}"));
-
- var text_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
- text_prop_builder.add ("{sv}", "type", new Variant.string ("string"));
- text_prop_builder.add ("{sv}", "description", new Variant.string ("The text to echo back"));
- properties_builder.add ("{sv}", "text", text_prop_builder.end ());
-
- builder.add ("{sv}", "properties", properties_builder.end ());
-
- var required_array_builder = new VariantBuilder (new VariantType ("as"));
- required_array_builder.add ("s", "text");
- builder.add ("{sv}", "required", required_array_builder.end ());
-
- var input_schema = builder.end ();
-
- var definition = new Mcp.Tools.Types.ToolDefinition ("echo", input_schema);
- definition.title = "Echo Tool";
- definition.description = "Echoes back the provided text";
-
- base (definition);
- }
-
- /**
- * {@inheritDoc}
- */
- protected override async Mcp.Tools.Types.CallToolResult do_execute (GLib.Variant arguments) throws Error {
- string text = get_string_arg (arguments, "text");
-
- return create_text_result ("Echo: %s".printf (text));
- }
- }
- /**
- * Calculator tool implementation.
- */
- public class CalculatorTool : Mcp.Tools.BaseExecutor {
- /**
- * Creates a new CalculatorTool.
- */
- public CalculatorTool () {
- // Create tool definition using Variant
- var builder = new VariantBuilder (new VariantType ("a{sv}"));
-
- // Add schema properties
- builder.add ("{sv}", "type", new Variant.string ("object"));
- builder.add ("{sv}", "description", new Variant.string ("Perform mathematical calculations"));
-
- var properties_builder = new VariantBuilder (new VariantType ("a{sv}"));
-
- // Expression property
- var expr_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
- expr_prop_builder.add ("{sv}", "type", new Variant.string ("string"));
- expr_prop_builder.add ("{sv}", "description", new Variant.string ("Mathematical expression to evaluate (e.g., '2 + 3 * 4')"));
- properties_builder.add ("{sv}", "expression", expr_prop_builder.end ());
-
- // Operation property
- var op_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
- op_prop_builder.add ("{sv}", "type", new Variant.string ("string"));
- op_prop_builder.add ("{sv}", "description", new Variant.string ("Operation: add, subtract, multiply, divide"));
-
- var enum_array_builder = new VariantBuilder (new VariantType ("as"));
- enum_array_builder.add ("s", "add");
- enum_array_builder.add ("s", "subtract");
- enum_array_builder.add ("s", "multiply");
- enum_array_builder.add ("s", "divide");
- op_prop_builder.add ("{sv}", "enum", enum_array_builder.end ());
- properties_builder.add ("{sv}", "operation", op_prop_builder.end ());
-
- // Operands property
- var operands_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
- operands_prop_builder.add ("{sv}", "type", new Variant.string ("array"));
- operands_prop_builder.add ("{sv}", "description", new Variant.string ("Array of numbers for the operation"));
-
- var items_schema_builder = new VariantBuilder (new VariantType ("a{sv}"));
- items_schema_builder.add ("{sv}", "type", new Variant.string ("number"));
- operands_prop_builder.add ("{sv}", "items", items_schema_builder.end ());
- properties_builder.add ("{sv}", "operands", operands_prop_builder.end ());
-
- builder.add ("{sv}", "properties", properties_builder.end ());
-
- var required_array_builder = new VariantBuilder (new VariantType ("as"));
- required_array_builder.add ("s", "expression");
- builder.add ("{sv}", "required", required_array_builder.end ());
-
- var input_schema = builder.end ();
-
- var definition = new Mcp.Tools.Types.ToolDefinition ("calculator", input_schema);
- definition.title = "Calculator";
- definition.description = "Perform mathematical calculations";
-
- base (definition);
- }
-
- /**
- * {@inheritDoc}
- */
- protected override async Mcp.Tools.Types.CallToolResult do_execute (GLib.Variant arguments) throws Error {
- string expression = get_string_arg (arguments, "expression");
- string operation = get_string_arg (arguments, "operation", "");
-
- // Parse operands if provided
- double[] operands = {};
- if (arguments.lookup_value ("operands", null) != null) {
- var operands_variant = arguments.lookup_value ("operands", new VariantType ("ad"));
- if (operands_variant != null) {
- // Get the array from variant using proper GLib.Variant API
- size_t n_elements;
- double* elements = (double*) operands_variant.get_data ();
- n_elements = operands_variant.n_children ();
-
- operands = new double[n_elements];
- for (size_t i = 0; i < n_elements; i++) {
- operands[i] = operands_variant.get_child_value (i).get_double ();
- }
- }
- }
-
- double result = 0.0;
-
- if (expression != "") {
- // Simple expression evaluation (in real implementation, use proper parser)
- try {
- result = evaluate_simple_expression (expression);
- } catch (Error e) {
- throw new Mcp.Core.McpError.INVALID_PARAMS ("Invalid expression: %s".printf (e.message));
- }
- } else if (operands.length > 0) {
- // Use operation with operands
- if (operands.length < 2) {
- throw new Mcp.Core.McpError.INVALID_PARAMS ("Operation requires at least 2 operands");
- }
-
- switch (operation) {
- case "add":
- result = operands[0] + operands[1];
- break;
- case "subtract":
- result = operands[0] - operands[1];
- break;
- case "multiply":
- result = operands[0] * operands[1];
- break;
- case "divide":
- if (operands[1] == 0) {
- throw new Mcp.Core.McpError.INVALID_PARAMS ("Division by zero");
- }
- result = operands[0] / operands[1];
- break;
- default:
- throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown operation: %s".printf (operation));
- }
- } else {
- throw new Mcp.Core.McpError.INVALID_PARAMS ("Either expression or operands must be provided");
- }
-
- // Create structured result using Variant
- var structured_data_builder = new VariantBuilder (new VariantType ("a{sv}"));
- structured_data_builder.add ("{sv}", "result", new Variant.double (result));
- structured_data_builder.add ("{sv}", "expression", new Variant.string (expression != "" ? expression : operation));
-
- var structured_data = structured_data_builder.end ();
-
- return create_structured_result ("Calculation result: %g".printf (result), structured_data);
- }
-
- /**
- * Evaluates a simple mathematical expression.
- *
- * @param expression The expression to evaluate
- * @return The result
- * @throws Error If evaluation fails
- */
- private double evaluate_simple_expression (string expression) throws Error {
- // Very simple expression evaluator for demonstration
- // In production, use a proper math expression parser
-
- // Handle basic operations
- if (expression.contains ("+")) {
- var parts = expression.split ("+");
- if (parts.length == 2) {
- double a = double.parse (parts[0].strip ());
- double b = double.parse (parts[1].strip ());
- return a + b;
- }
- } else if (expression.contains ("-")) {
- var parts = expression.split ("-");
- if (parts.length == 2) {
- double a = double.parse (parts[0].strip ());
- double b = double.parse (parts[1].strip ());
- return a - b;
- }
- } else if (expression.contains ("*")) {
- var parts = expression.split ("*");
- if (parts.length == 2) {
- double a = double.parse (parts[0].strip ());
- double b = double.parse (parts[1].strip ());
- return a * b;
- }
- } else if (expression.contains ("/")) {
- var parts = expression.split ("/");
- if (parts.length == 2) {
- double a = double.parse (parts[0].strip ());
- double b = double.parse (parts[1].strip ());
- if (b == 0) {
- throw new Mcp.Core.McpError.INVALID_PARAMS ("Division by zero");
- }
- return a / b;
- }
- }
-
- // Try to parse as single number
- return double.parse (expression);
- }
- }
- /**
- * File operations tool implementation.
- */
- public class FileOperationTool : Mcp.Tools.BaseExecutor {
- /**
- * Creates a new FileOperationTool.
- */
- public FileOperationTool () {
- // Create tool definition using Variant
- var builder = new VariantBuilder (new VariantType ("a{sv}"));
-
- // Add schema properties
- builder.add ("{sv}", "type", new Variant.string ("object"));
- builder.add ("{sv}", "description", new Variant.string ("Perform file operations"));
-
- var properties_builder = new VariantBuilder (new VariantType ("a{sv}"));
-
- // Operation property
- var op_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
- op_prop_builder.add ("{sv}", "type", new Variant.string ("string"));
- op_prop_builder.add ("{sv}", "description", new Variant.string ("Operation: read, write, list, delete"));
-
- var enum_array_builder = new VariantBuilder (new VariantType ("as"));
- enum_array_builder.add ("s", "read");
- enum_array_builder.add ("s", "write");
- enum_array_builder.add ("s", "list");
- enum_array_builder.add ("s", "delete");
- op_prop_builder.add ("{sv}", "enum", enum_array_builder.end ());
- properties_builder.add ("{sv}", "operation", op_prop_builder.end ());
-
- // Path property
- var path_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
- path_prop_builder.add ("{sv}", "type", new Variant.string ("string"));
- path_prop_builder.add ("{sv}", "description", new Variant.string ("File path"));
- properties_builder.add ("{sv}", "path", path_prop_builder.end ());
-
- // Content property (for write operation)
- var content_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
- content_prop_builder.add ("{sv}", "type", new Variant.string ("string"));
- content_prop_builder.add ("{sv}", "description", new Variant.string ("Content to write (for write operation)"));
- properties_builder.add ("{sv}", "content", content_prop_builder.end ());
-
- builder.add ("{sv}", "properties", properties_builder.end ());
-
- var required_array_builder = new VariantBuilder (new VariantType ("as"));
- required_array_builder.add ("s", "operation");
- required_array_builder.add ("s", "path");
- builder.add ("{sv}", "required", required_array_builder.end ());
-
- var input_schema = builder.end ();
-
- var definition = new Mcp.Tools.Types.ToolDefinition ("file_ops", input_schema);
- definition.title = "File Operations";
- definition.description = "Perform basic file operations";
-
- base (definition);
- }
-
- /**
- * {@inheritDoc}
- */
- protected override async Mcp.Tools.Types.CallToolResult do_execute (GLib.Variant arguments) throws Error {
- string operation = get_string_arg (arguments, "operation");
- string path = get_string_arg (arguments, "path");
- string content = get_string_arg (arguments, "content", "");
-
- switch (operation) {
- case "read":
- return yield handle_read (path);
- case "write":
- return yield handle_write (path, content);
- case "list":
- return yield handle_list (path);
- case "delete":
- return yield handle_delete (path);
- default:
- throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown operation: %s".printf (operation));
- }
- }
-
- /**
- * Handles file read operation.
- *
- * @param path The file path
- * @return The operation result
- * @throws Error If reading fails
- */
- private async Mcp.Tools.Types.CallToolResult handle_read (string path) throws Error {
- var file = File.new_for_path (path);
- if (!file.query_exists ()) {
- throw new Mcp.Core.McpError.RESOURCE_NOT_FOUND ("File not found: %s".printf (path));
- }
-
- uint8[] contents;
- string etag;
- yield file.load_contents_async (null, out contents, out etag);
- string text = (string) contents;
-
- return create_text_result ("File content:\n%s".printf (text));
- }
-
- /**
- * Handles file write operation.
- *
- * @param path The file path
- * @param content The content to write
- * @return The operation result
- * @throws Error If writing fails
- */
- private async Mcp.Tools.Types.CallToolResult handle_write (string path, string content) throws Error {
- var file = File.new_for_path (path);
-
- // Create parent directories if needed
- var parent = file.get_parent ();
- if (parent != null && !parent.query_exists ()) {
- try {
- parent.make_directory_with_parents ();
- } catch (Error e) {
- throw new Mcp.Core.McpError.INTERNAL_ERROR ("Failed to create parent directory: %s".printf (e.message));
- }
- }
-
- uint8[] data = content.data;
- string etag_out;
- try {
- yield file.replace_contents_async (
- data,
- null,
- false,
- FileCreateFlags.REPLACE_DESTINATION,
- null,
- out etag_out
- );
- } catch (Error e) {
- throw new Mcp.Core.McpError.INTERNAL_ERROR ("Failed to write file: %s".printf (e.message));
- }
-
- return create_text_result ("Wrote %u bytes to %s".printf (data.length, path));
- }
-
- /**
- * Handles file list operation.
- *
- * @param path The directory path
- * @return The operation result
- * @throws Error If listing fails
- */
- private async Mcp.Tools.Types.CallToolResult handle_list (string path) throws Error {
- var dir = File.new_for_path (path);
- if (!dir.query_exists ()) {
- throw new Mcp.Core.McpError.RESOURCE_NOT_FOUND ("Directory not found: %s".printf (path));
- }
-
- var enumerator = yield dir.enumerate_children_async (
- "standard::name,standard::type,standard::size",
- FileQueryInfoFlags.NONE,
- Priority.DEFAULT,
- null
- );
-
- string[] entries = {};
- FileInfo? file_info = null;
- while ((file_info = enumerator.next_file ()) != null) {
- string entry = "%s (%s)".printf (
- file_info.get_name (),
- file_info.get_file_type () == FileType.DIRECTORY ? "dir" : "file"
- );
- entries += entry;
- }
-
- return create_text_result ("Directory listing:\n%s".printf (string.joinv ("\n", entries)));
- }
-
- /**
- * Handles file delete operation.
- *
- * @param path The file path
- * @return The operation result
- * @throws Error If deletion fails
- */
- private async Mcp.Tools.Types.CallToolResult handle_delete (string path) throws Error {
- var file = File.new_for_path (path);
- if (!file.query_exists ()) {
- throw new Mcp.Core.McpError.RESOURCE_NOT_FOUND ("File not found: %s".printf (path));
- }
-
- yield file.delete_async ();
-
- return create_text_result ("Deleted: %s".printf (path));
- }
- }
- /**
- * Simple file resource provider implementation.
- */
- public class FileResourceProvider : Mcp.Resources.BaseProvider {
- /**
- * Creates a new FileResourceProvider.
- */
- public FileResourceProvider () {
- Object ();
- }
-
- /**
- * {@inheritDoc}
- */
- public override async Gee.ArrayList<Mcp.Resources.Types.Resource> list_resources (string? cursor) throws Error {
- var resources = new Gee.ArrayList<Mcp.Resources.Types.Resource> ();
-
- // List files in current directory
- var dir = File.new_for_path (".");
- var enumerator = yield dir.enumerate_children_async (
- "standard::name,standard::type,standard::size",
- FileQueryInfoFlags.NONE,
- Priority.DEFAULT,
- null
- );
-
- FileInfo? file_info = null;
- while ((file_info = enumerator.next_file ()) != null) {
- if (file_info.get_file_type () == FileType.REGULAR) {
- var file = File.new_for_path (file_info.get_name ());
- var resource = new Mcp.Resources.Types.Resource (
- file.get_uri (),
- file_info.get_name ()
- );
- resource.mime_type = guess_mime_type (file_info.get_name ());
- resource.size = file_info.get_size ();
-
- resources.add (resource);
- }
- }
-
- return resources;
- }
-
- /**
- * {@inheritDoc}
- */
- public override async Gee.ArrayList<Mcp.Types.Common.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;
- string etag;
- yield file.load_contents_async (null, out contents, out etag);
-
- string text = (string) contents;
-
- var result = new Gee.ArrayList<Mcp.Types.Common.ResourceContents> ();
- result.add (new Mcp.Types.Common.TextResourceContents (uri, text));
-
- return result;
- }
-
- /**
- * Guesses MIME type from filename.
- *
- * @param filename The filename
- * @return The guessed MIME type
- */
- private new string guess_mime_type (string filename) {
- // Simple MIME type guessing based on extension
- string extension = filename.down ();
-
- if (extension == "txt") {
- return "text/plain";
- } else if (extension == "json") {
- return "application/json";
- } else if (extension == "xml") {
- return "application/xml";
- } else {
- return "application/octet-stream";
- }
- }
- }
- /**
- * In-memory resource provider with subscription support.
- */
- public class MemoryResourceProvider : Mcp.Resources.BaseProvider {
- private HashTable<string, string> resources;
- private uint32 next_id;
-
- /**
- * Creates a new MemoryResourceProvider.
- */
- public MemoryResourceProvider () {
- Object ();
- resources = new HashTable<string, string> (str_hash, str_equal);
- next_id = 1;
-
- // Add some initial resources
- resources.insert ("memory://note/1", "This is a sample note in memory.");
- resources.insert ("memory://note/2", "Another note with some content.");
- resources.insert ("memory://counter", "0");
- }
-
- /**
- * {@inheritDoc}
- */
- public override async Gee.ArrayList<Mcp.Resources.Types.Resource> list_resources (string? cursor) throws Error {
- var result = new Gee.ArrayList<Mcp.Resources.Types.Resource> ();
-
- foreach (var uri in resources.get_keys ()) {
- var resource = new Mcp.Resources.Types.Resource (uri, get_name_from_uri (uri));
- resource.mime_type = "text/plain";
- resource.size = resources[uri].length;
-
- result.add (resource);
- }
-
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- public override async Gee.ArrayList<Mcp.Types.Common.ResourceContents> read_resource (string uri) throws Error {
- if (!resources.contains (uri)) {
- throw new Mcp.Core.McpError.RESOURCE_NOT_FOUND ("Resource not found: %s".printf (uri));
- }
-
- var result = new Gee.ArrayList<Mcp.Types.Common.ResourceContents> ();
- result.add (new Mcp.Types.Common.TextResourceContents (uri, resources[uri]));
-
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- public override async void subscribe (string uri) throws Error {
- if (!resources.contains (uri)) {
- throw new Mcp.Core.McpError.RESOURCE_NOT_FOUND ("Resource not found: %s".printf (uri));
- }
-
- // BaseProvider will handle subscription tracking
- yield base.subscribe (uri);
- }
-
- /**
- * Updates a resource and notifies subscribers.
- *
- * @param uri The URI of the resource to update
- * @param content The new content
- */
- public void update_resource (string uri, string content) {
- if (!resources.contains (uri)) {
- return;
- }
-
- resources[uri] = content;
- notify_resource_updated (uri);
- }
-
- /**
- * Creates a new note resource.
- *
- * @param title The title of the note
- * @param content The content of the note
- * @return The URI of the new resource
- */
- public string create_note (string title, string content) {
- string uri = "memory://note/%u".printf (next_id++);
- resources.insert (uri, "Title: %s\n\n%s".printf (title, content));
-
- // The ResourceManager will handle list_changed notifications
- // when resources are listed
-
- return uri;
- }
-
- /**
- * Increments the counter resource.
- *
- * @return The new counter value
- */
- public int increment_counter () {
- string uri = "memory://counter";
- if (!resources.contains (uri)) {
- resources.insert (uri, "0");
- }
-
- int value = int.parse (resources[uri]);
- value++;
- resources[uri] = value.to_string ();
-
- // Notify subscribers
- notify_resource_updated (uri);
-
- return value;
- }
-
- /**
- * Extracts name from URI.
- *
- * @param uri The URI
- * @return The name
- */
- private string get_name_from_uri (string uri) {
- var parts = uri.split ("/");
- return parts[parts.length - 1];
- }
-
- }
- /**
- * Code review prompt template implementation.
- */
- public class CodeReviewPromptTemplate : Mcp.Prompts.BaseTemplate {
- /**
- * Creates a new CodeReviewPromptTemplate.
- */
- public CodeReviewPromptTemplate () {
- base ("code_review", "Code Review", "Generates a code review prompt for analyzing code quality and best practices");
-
- // Add arguments
- add_argument ("code", "Code", "The code to review", true);
- add_argument ("language", "Language", "Programming language of the code", false);
- add_argument ("focus", "Focus Area", "Specific areas to focus on (e.g., security, performance, readability)", false);
- }
-
- /**
- * {@inheritDoc}
- */
- protected override Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> generate_messages (GLib.Variant arguments) {
- var messages = new Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> ();
-
- string language = "";
- if (arguments.lookup_value ("language", null) != null) {
- language = arguments.lookup_value ("language", new VariantType ("s")).get_string ();
- }
-
- string focus = "";
- if (arguments.lookup_value ("focus", null) != null) {
- focus = arguments.lookup_value ("focus", new VariantType ("s")).get_string ();
- }
-
- string template = """Please review the following {{language}} code:
- ```{{language}}
- {{code}}
- ```
- {{#focus}}
- Please focus your review on: {{focus}}
- {{/focus}}
- Please analyze:
- 1. Code quality and readability
- 2. Potential bugs or issues
- 3. Performance considerations
- 4. Security vulnerabilities
- 5. Adherence to best practices
- 6. Suggestions for improvement
- Provide specific, actionable feedback.""";
-
- messages.add (create_user_message (template, arguments));
- return messages;
- }
- }
- /**
- * Summary prompt template implementation.
- */
- public class SummaryPromptTemplate : Mcp.Prompts.BaseTemplate {
- /**
- * Creates a new SummaryPromptTemplate.
- */
- public SummaryPromptTemplate () {
- base ("summary", "Text Summary", "Generates a summary of the provided text");
-
- // Add arguments
- add_argument ("text", "Text", "The text to summarize", true);
- add_argument ("length", "Summary Length", "Desired length of the summary (short, medium, long)", false);
- add_argument ("style", "Summary Style", "Style of the summary (bullet_points, paragraph, executive)", false);
- }
-
- /**
- * {@inheritDoc}
- */
- protected override Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> generate_messages (GLib.Variant arguments) {
- var messages = new Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> ();
-
- string length = "medium";
- if (arguments.lookup_value ("length", null) != null) {
- length = arguments.lookup_value ("length", new VariantType ("s")).get_string ();
- }
-
- string style = "paragraph";
- if (arguments.lookup_value ("style", null) != null) {
- style = arguments.lookup_value ("style", new VariantType ("s")).get_string ();
- }
-
- string template = """Please provide a {{length}} summary of the following text:
- {{text}}
- Please format the summary as {{style}}.
- {{#style}}
- {{#bullet_points}}
- Use bullet points for key points.
- {{/bullet_points}}
- {{#paragraph}}
- Write in a clear, concise paragraph.
- {{/paragraph}}
- {{#executive}}
- Provide an executive summary with key takeaways.
- {{/executive}}
- {{/style}}""";
-
- messages.add (create_user_message (template, arguments));
- return messages;
- }
- }
- /**
- * Explain prompt template implementation.
- */
- public class ExplainPromptTemplate : Mcp.Prompts.BaseTemplate {
- /**
- * Creates a new ExplainPromptTemplate.
- */
- public ExplainPromptTemplate () {
- base ("explain", "Explain Concept", "Generates an explanation of a concept or topic");
-
- // Add arguments
- add_argument ("topic", "Topic", "The concept or topic to explain", true);
- add_argument ("audience", "Audience", "Target audience level (beginner, intermediate, advanced)", false);
- add_argument ("depth", "Depth", "Depth of explanation (brief, detailed, comprehensive)", false);
- add_argument ("examples", "Include Examples", "Whether to include examples", false);
- }
-
- /**
- * {@inheritDoc}
- */
- protected override Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> generate_messages (GLib.Variant arguments) {
- var messages = new Gee.ArrayList<Mcp.Prompts.Types.PromptMessage> ();
-
- string audience = "intermediate";
- if (arguments.lookup_value ("audience", null) != null) {
- audience = arguments.lookup_value ("audience", new VariantType ("s")).get_string ();
- }
-
- string depth = "detailed";
- if (arguments.lookup_value ("depth", null) != null) {
- depth = arguments.lookup_value ("depth", new VariantType ("s")).get_string ();
- }
-
- bool include_examples = false;
- if (arguments.lookup_value ("examples", null) != null) {
- include_examples = arguments.lookup_value ("examples", new VariantType ("b")).get_boolean ();
- }
-
- string template = """Please explain the concept of "{{topic}}" for a {{audience}} audience.
- Provide a {{depth}} explanation that covers:
- 1. Definition and core concepts
- 2. Key principles and mechanisms
- 3. Practical applications and use cases
- 4. Common challenges and considerations
- {{#examples}}
- Please include relevant examples to illustrate the concept.
- {{/examples}}
- Tailor your explanation to the specified audience level and ensure clarity and accuracy.""";
-
- // Create a modified arguments variant for examples
- var builder = new VariantBuilder (new VariantType ("a{sv}"));
-
- // Copy all existing arguments
- var iter = arguments.iterator ();
- string key;
- Variant value;
- while (iter.next ("{sv}", out key, out value)) {
- builder.add ("{sv}", key, value);
- }
-
- // Add/override the examples flag
- builder.add ("{sv}", "examples", new Variant.boolean (include_examples));
-
- var modified_args = builder.end ();
-
- messages.add (create_user_message (template, modified_args));
- return messages;
- }
- }
- /**
- * Main function.
- *
- * @param args Command line arguments
- * @return Exit code
- */
- public static int main (string[] args) {
- var server = new SimpleServer ();
-
- // Create a main loop
- var loop = new MainLoop ();
-
- server.run.begin ((obj, res) => {
- loop.quit ();
- });
-
- loop.run ();
- return 0;
- }
- /**
- Content-Length: 54
- {"jsonrpc":"2.0","id":1,"method":"initialize"}
- */
|