mirror of
https://github.com/gnh1201/welsonjs.git
synced 2026-04-18 18:18:42 +00:00
Forward the JSON-RPC request id through the dispatcher and handler so methods can access the id. JsonRpc2Dispatcher now passes the id to dispatchMethodAsync, and the JsonRpc2 endpoint lambda accepts the id parameter. Implemented a call for "tools/call" that extracts the tool name via ser.ExtractFrom(id, "params", "name") and invokes a new ResolveToolsCall(string) stub (TODO: implement actual tool logic). This prepares the codepath for tooling invocation based on request params.
102 lines
3.3 KiB
C#
102 lines
3.3 KiB
C#
using log4net;
|
|
using System;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace WelsonJS.Launcher.ApiEndpoints
|
|
{
|
|
public class JsonRpc2 : IApiEndpoint
|
|
{
|
|
private readonly ResourceServer Server;
|
|
private readonly HttpClient _httpClient;
|
|
private readonly ILog _logger;
|
|
private const string Prefix = "jsonrpc2";
|
|
|
|
public JsonRpc2(ResourceServer server, HttpClient httpClient, ILog logger)
|
|
{
|
|
Server = server;
|
|
|
|
_httpClient = httpClient;
|
|
_logger = logger;
|
|
}
|
|
|
|
public bool CanHandle(HttpListenerContext context, string path)
|
|
{
|
|
if (context == null)
|
|
return false;
|
|
|
|
if (!string.Equals(context.Request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase))
|
|
return false;
|
|
|
|
if (path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase) == false)
|
|
return false;
|
|
|
|
string contentType = context.Request.ContentType?.ToLowerInvariant() ?? string.Empty;
|
|
if (!(contentType.StartsWith("application/json")
|
|
|| contentType.StartsWith("application/json-rpc")
|
|
|| contentType.StartsWith("application/jsonrpc")
|
|
|| contentType.StartsWith("text/json")))
|
|
return false;
|
|
|
|
if (!context.Request.HasEntityBody)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public async Task HandleAsync(HttpListenerContext context, string path)
|
|
{
|
|
string body;
|
|
try
|
|
{
|
|
using (var input = context.Request.InputStream)
|
|
using (var reader = new System.IO.StreamReader(input, System.Text.Encoding.UTF8))
|
|
{
|
|
body = await reader.ReadToEndAsync();
|
|
}
|
|
|
|
_logger.Debug($"[JsonRpc2] Request body received ({body.Length} bytes)");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error("[JsonRpc2] Failed to read request body", ex);
|
|
|
|
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
|
context.Response.Close();
|
|
return;
|
|
}
|
|
|
|
var dispatcher = new JsonRpc2Dispatcher(_logger);
|
|
|
|
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(300)))
|
|
{
|
|
await dispatcher.HandleAsync(
|
|
body,
|
|
async (method, id, ser, ct) =>
|
|
{
|
|
switch (method)
|
|
{
|
|
case "tools/list":
|
|
await Server.ServeResource(context, ResourceServer.GetResource("McpToolsList.json"), "application/json");
|
|
break;
|
|
|
|
case "tools/call":
|
|
await ResolveToolsCall(ser.ExtractFrom(id, "params", "name"));
|
|
break;
|
|
}
|
|
|
|
return string.Empty;
|
|
},
|
|
cts.Token);
|
|
}
|
|
}
|
|
|
|
private async Task ResolveToolsCall(string toolsName)
|
|
{
|
|
// TODO: ex) get_weather
|
|
}
|
|
}
|
|
}
|