diff --git a/src/.idea/.idea.cs-mic-mcp/.idea/.gitignore b/src/.idea/.idea.cs-mic-mcp/.idea/.gitignore new file mode 100644 index 0000000..4d87aa1 --- /dev/null +++ b/src/.idea/.idea.cs-mic-mcp/.idea/.gitignore @@ -0,0 +1,15 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Rider ignored files +/modules.xml +/contentModel.xml +/projectSettingsUpdater.xml +/.idea.cs-mic-mcp.iml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/src/.idea/.idea.cs-mic-mcp/.idea/encodings.xml b/src/.idea/.idea.cs-mic-mcp/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/src/.idea/.idea.cs-mic-mcp/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/.idea/.idea.cs-mic-mcp/.idea/indexLayout.xml b/src/.idea/.idea.cs-mic-mcp/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/src/.idea/.idea.cs-mic-mcp/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/.idea/.idea.cs-mic-mcp/.idea/misc.xml b/src/.idea/.idea.cs-mic-mcp/.idea/misc.xml new file mode 100644 index 0000000..aafa249 --- /dev/null +++ b/src/.idea/.idea.cs-mic-mcp/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/src/.idea/.idea.cs-mic-mcp/.idea/vcs.xml b/src/.idea/.idea.cs-mic-mcp/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/src/.idea/.idea.cs-mic-mcp/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/cs-mic-mcp.sln b/src/cs-mic-mcp.sln new file mode 100644 index 0000000..e2baae5 --- /dev/null +++ b/src/cs-mic-mcp.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cs-mic-mcp", "cs-mic-mcp\cs-mic-mcp.csproj", "{09B4A809-D9D3-445C-977B-0FDA6E903F03}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {09B4A809-D9D3-445C-977B-0FDA6E903F03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09B4A809-D9D3-445C-977B-0FDA6E903F03}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09B4A809-D9D3-445C-977B-0FDA6E903F03}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09B4A809-D9D3-445C-977B-0FDA6E903F03}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/src/cs-mic-mcp/Program.cs b/src/cs-mic-mcp/Program.cs new file mode 100644 index 0000000..ab9c278 --- /dev/null +++ b/src/cs-mic-mcp/Program.cs @@ -0,0 +1,55 @@ +using cs_mic_mcp.Resources; +using cs_mic_mcp.Tools; + +namespace cs_mic_mcp; + +public class Program +{ + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + builder.Services + .AddMcpServer() + //.WithStdioServerTransport() + .WithHttpTransport() + .WithTools() + .WithResources(); + + builder.Services.AddCors(options => + { + options.AddDefaultPolicy(policy => + { + policy + .AllowAnyOrigin() + .AllowAnyHeader() + .AllowAnyMethod() + .WithExposedHeaders("Mcp-Session-Id"); + }); + }); + + // Add services to the container. + + //builder.Services.AddControllers(); + + // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi + //builder.Services.AddOpenApi(); + + var app = builder.Build(); + app.UseCors(); + + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + //app.MapOpenApi(); + } + + //app.UseAuthorization(); + + + //app.MapControllers(); + app.MapMcp("/mcp"); + + app.Run(); + } +} \ No newline at end of file diff --git a/src/cs-mic-mcp/Properties/launchSettings.json b/src/cs-mic-mcp/Properties/launchSettings.json new file mode 100644 index 0000000..089f4eb --- /dev/null +++ b/src/cs-mic-mcp/Properties/launchSettings.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5017", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/cs-mic-mcp/Resources/DocumentationResources.cs b/src/cs-mic-mcp/Resources/DocumentationResources.cs new file mode 100644 index 0000000..82bc346 --- /dev/null +++ b/src/cs-mic-mcp/Resources/DocumentationResources.cs @@ -0,0 +1,29 @@ +using System.ComponentModel; +using cs_mic_mcp.Tools; +using ModelContextProtocol.Server; + +namespace cs_mic_mcp.Resources; + +/// +/// Provides resources related to documentation for the cs-mic-mcp application. +/// Includes methods for accessing function references supported by the cs-mic expression parser. +/// +[McpServerResourceType] +public class DocumentationResources +{ + /// + /// Retrieves a formatted list of functions supported by the cs-mic expression parser. + /// + /// + /// A string containing function names and their expected arguments, formatted as lines of text. + /// + [McpServerResource] + [Description("Reference for functions supported by cs-mic expressions.")] + public static string GetFunctions() + { + var functions = string.Join(Environment.NewLine, + MathTools.standardLibraryFunctions.Select(MathTools.PrintFunctionInfo)); + + return functions; + } +} \ No newline at end of file diff --git a/src/cs-mic-mcp/Tools/MathTools.cs b/src/cs-mic-mcp/Tools/MathTools.cs new file mode 100644 index 0000000..0552c6b --- /dev/null +++ b/src/cs-mic-mcp/Tools/MathTools.cs @@ -0,0 +1,120 @@ +using System.ComponentModel; +using System.Globalization; +using ModelContextProtocol.Server; +using CSMic; +using CapyKit.Extensions; + +namespace cs_mic_mcp.Tools; + +/// +/// Provides tools for evaluating mathematical expressions and searching for supported functions. +/// This class interacts with the cs-mic expression parser to perform deterministic evaluations +/// and function searches. It is designed to be used as part of the McpServer infrastructure. +/// +[McpServerToolType] +public class MathTools +{ + /// + /// A collection of standard library functions supported by the cs-mic expression parser. + /// These functions represent instances of and are dynamically + /// determined at runtime by inspecting the relevant assembly for compatible types. The collection + /// is intended to provide the list of mathematical or computational functions available for use + /// when evaluating expressions or searching for specific operations. + /// + internal static IEnumerable standardLibraryFunctions; + + /// + /// Provides tools for evaluating mathematical expressions and searching for available mathematical + /// functions using the cs-mic expression parser library. This class is intended to simplify tasks + /// related to mathematical computations and function discovery. + /// + static MathTools() + { + MathTools.standardLibraryFunctions = typeof(CSMic.StandardLibrary.Initializer).Assembly + .GetTypes() + .Where(type => !type.IsAbstract && typeof(ICodedFunction).IsAssignableFrom(type)) + .Select(Activator.CreateInstance) + .OfType(); + } + + /// + /// Evaluates a mathematical expression deterministically using the cs-mic expression parser. + /// This method computes the result of the expression and returns it as a string. + /// + /// + /// A string containing the mathematical expression to be evaluated. + /// The expression should conform to the syntax and function definitions supported by the cs-mic library. + /// + /// + /// A string representing the result of the evaluated expression. If the result is a numeric value, + /// it is formatted using the invariant culture. + /// + [McpServerTool] + [Description( + "Evaluate mathematical expressions deterministically using cs-mic, an expression parser. Use this tool instead of calculating arithmetic operations yourself. See the cs-mic function reference resource for supported functions.")] + public static string Calculate(string expression) + { + var inputInterpreter = new InputInterpreter(); + CSMic.StandardLibrary.Initializer.InitializeAll(inputInterpreter); + inputInterpreter.Interpret(expression); + var result = + inputInterpreter.StringValue.IfNullOrWhiteSpace( + inputInterpreter.NumericValue.ToString(CultureInfo.InvariantCulture)); + return result; + } + + /// + /// Searches for mathematical functions that match the provided expression within the cs-mic standard library. + /// This method allows users to determine whether a function exists and understand its syntax or arguments. + /// + /// + /// A string representing the search term. It can match either the function name or any of its expected argument names, + /// and the comparison is case-insensitive. + /// + /// + /// An enumerable collection of strings, each providing information about a matching function, including its name + /// and expected arguments. + /// + [McpServerTool] + [Description( + "Search the functions supported by cs-mic. Use this when you need to know whether a mathematical function exists or what syntax it uses. If the search expression is empty, all functions are returned.")] + public static IEnumerable Search(string expression) + { + if (string.IsNullOrWhiteSpace(expression)) + { + foreach (var function in MathTools.standardLibraryFunctions) + { + yield return PrintFunctionInfo(function); + } + } + else + { + expression = expression.ToLower().Trim(); + foreach (var function in MathTools.standardLibraryFunctions.Where(f => + f.Name.Contains(expression, StringComparison.InvariantCultureIgnoreCase) || + f.ExpectedArguments.Any(ea => + ea.Name.Contains(expression, StringComparison.InvariantCultureIgnoreCase)))) + { + yield return PrintFunctionInfo(function); + } + } + } + + /// + /// Generates a string representation of a mathematical function, including its name and expected arguments. + /// The output describes the function in a readable format, where the function name is followed by a list of + /// argument names if applicable. + /// + /// + /// An object representing the mathematical function whose details are to be formatted. The function should include + /// its name and a collection of expected arguments. + /// + /// + /// A string containing the function name followed by its expected arguments, separated by commas. If the function + /// has no arguments, the string will only contain the function name. + /// + internal static string PrintFunctionInfo(ICodedFunction function) + { + return $"{function.Name}({string.Join(", ", function.ExpectedArguments.Select(ea => ea.Name))})"; + } +} \ No newline at end of file diff --git a/src/cs-mic-mcp/appsettings.Development.json b/src/cs-mic-mcp/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/src/cs-mic-mcp/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/cs-mic-mcp/appsettings.json b/src/cs-mic-mcp/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/src/cs-mic-mcp/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/cs-mic-mcp/cs-mic-mcp.csproj b/src/cs-mic-mcp/cs-mic-mcp.csproj new file mode 100644 index 0000000..15b7691 --- /dev/null +++ b/src/cs-mic-mcp/cs-mic-mcp.csproj @@ -0,0 +1,18 @@ + + + + net10.0 + enable + enable + cs_mic_mcp + + + + + + + + + + +