diff --git a/GenHTTP.slnx b/GenHTTP.slnx
index a1d3af5d7..b839e75e9 100644
--- a/GenHTTP.slnx
+++ b/GenHTTP.slnx
@@ -28,6 +28,7 @@
+
diff --git a/Modules/Mcp/GenHTTP.Modules.Mcp.csproj b/Modules/Mcp/GenHTTP.Modules.Mcp.csproj
new file mode 100644
index 000000000..968795b3a
--- /dev/null
+++ b/Modules/Mcp/GenHTTP.Modules.Mcp.csproj
@@ -0,0 +1,24 @@
+
+
+
+
+ Allows to provide tools for LLMs via the MCP.
+ HTTP Webserver C# Module MCP LLM Tool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Modules/Mcp/ITool.cs b/Modules/Mcp/ITool.cs
new file mode 100644
index 000000000..604d71934
--- /dev/null
+++ b/Modules/Mcp/ITool.cs
@@ -0,0 +1,29 @@
+namespace GenHTTP.Modules.Mcp;
+
+public interface ITool
+{
+
+ string Name { get; }
+
+ string Description { get; }
+
+ internal Type InputType { get; }
+
+ internal Type OutputType { get; }
+
+ internal object CallUntyped(object input);
+
+}
+
+public interface ITool : ITool
+{
+
+ TOutput Call(TInput input);
+
+ Type ITool.InputType => typeof(TInput);
+
+ Type ITool.OutputType => typeof(TOutput);
+
+ object ITool.CallUntyped(object input) => Call(((TInput)input)!)!;
+
+}
diff --git a/Modules/Mcp/Logic/ToolsHandler.cs b/Modules/Mcp/Logic/ToolsHandler.cs
new file mode 100644
index 000000000..d78d226fa
--- /dev/null
+++ b/Modules/Mcp/Logic/ToolsHandler.cs
@@ -0,0 +1,160 @@
+using System.Text.Json;
+
+using GenHTTP.Api.Content;
+using GenHTTP.Api.Protocol;
+
+using GenHTTP.Modules.Mcp.Types;
+using GenHTTP.Modules.Reflection;
+using GenHTTP.Modules.Websockets;
+
+using NJsonSchema;
+
+namespace GenHTTP.Modules.Mcp.Logic;
+
+public class ToolsHandler : IHandler
+{
+ private static readonly JsonSerializerOptions SerializationOptions = new()
+ {
+ PropertyNameCaseInsensitive = true,
+ ReadCommentHandling = JsonCommentHandling.Skip,
+ AllowTrailingCommas = true
+ };
+
+ private readonly IHandler _Websocket;
+
+ private readonly Dictionary _Tools;
+
+ #region Initialization
+
+ public ToolsHandler(List tools)
+ {
+ _Tools = tools.ToDictionary(t => t.Name, t => t);
+
+ _Websocket = Websocket.Create()
+ .OnMessage(DispatchMessage)
+ .Build();
+ }
+
+ #endregion
+
+ #region Functionality
+
+ public ValueTask PrepareAsync() => ValueTask.CompletedTask;
+
+ public ValueTask HandleAsync(IRequest request) => _Websocket.HandleAsync(request);
+
+ private async Task DispatchMessage(IWebsocketConnection connection, string message)
+ {
+ var request = JsonSerializer.Deserialize(message, SerializationOptions);
+
+ if (request == null)
+ {
+ throw new ArgumentException("Unable read JsonRpc frame from message");
+ }
+
+ switch (request.Method)
+ {
+ case "tools/list":
+ {
+ var response = new JsonRpcResponse
+ {
+ Id = request.Id,
+ Result = ListTools()
+ };
+
+ await connection.SendAsync(JsonSerializer.Serialize(response));
+ break;
+ }
+ case "tools/call":
+ {
+ var arguments = request.Params?.Deserialize();
+
+ if (arguments?.Name is not null)
+ {
+ if (_Tools.TryGetValue(arguments.Name, out var tool))
+ {
+ try
+ {
+ var result = await CallTool(tool, arguments.Arguments);
+
+ var response = new JsonRpcResponse