mirror of
https://github.com/gnh1201/welsonjs.git
synced 2026-04-19 02:28:41 +00:00
Pass the serializer and request id to ResolveToolsCall and implement a basic dispatcher that extracts params.method. Add a handler stub for "run_jsrt_script" (extracts the script argument; implementation TODO) and log unknown tool methods. Also update McpToolsList.json scriptContract notes from Korean to English to improve readability/localization.
117 lines
3.7 KiB
C#
117 lines
3.7 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, ser, id, ct) =>
|
|
{
|
|
switch (method)
|
|
{
|
|
case "tools/list":
|
|
await Server.ServeResource(context, ResourceServer.GetResource("McpToolsList.json"), "application/json");
|
|
break;
|
|
|
|
case "tools/call":
|
|
await ResolveToolsCall(ser, id);
|
|
break;
|
|
}
|
|
|
|
return string.Empty;
|
|
},
|
|
cts.Token);
|
|
}
|
|
}
|
|
|
|
private async Task ResolveToolsCall(JsSerializer ser, int id)
|
|
{
|
|
var toolsName = ser.ExtractFrom(id, "params", "method")?.Trim();
|
|
|
|
switch (toolsName)
|
|
{
|
|
case "run_jsrt_script":
|
|
{
|
|
var script = ser.ExtractFrom(id, "params", "arguments", "script")?.Trim();
|
|
|
|
// todo
|
|
}
|
|
break;
|
|
|
|
default:
|
|
_logger.Warn($"[JsonRpc2] Unknown tools method: {toolsName}");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|