149 lines
5.7 KiB
C#
149 lines
5.7 KiB
C#
using Microsoft.Extensions.DependencyInjection;
|
||
using Microsoft.Extensions.Hosting;
|
||
using ModelContextProtocol.Client;
|
||
using ModelContextProtocol.Protocol;
|
||
using System.Text.Encodings.Web;
|
||
using System.Text.Json;
|
||
using System.Text.Json.Nodes;
|
||
using XiaoZhiSharp_ConsoleApp.McpTools;
|
||
|
||
namespace XiaoZhiSharp_ConsoleApp.Services
|
||
{
|
||
public class McpService
|
||
{
|
||
private static IHost? _host;
|
||
private static IMcpClient _mcpClient;
|
||
public McpService()
|
||
{
|
||
var builder = Host.CreateApplicationBuilder();
|
||
|
||
var mcpBuilder = builder.Services
|
||
.AddMcpServer()
|
||
.WithStreamServerTransport(Global.McpClientToServerPipe.Reader.AsStream(), Global.McpServerToClientPipe.Writer.AsStream())
|
||
.WithTools<IotThings_Tool>();
|
||
|
||
_host = builder.Build();
|
||
_host.StartAsync();
|
||
}
|
||
|
||
public async Task<string> McpMessageHandle(string message)
|
||
{
|
||
try
|
||
{
|
||
if (_mcpClient == null)
|
||
{
|
||
var clientTransport = new StreamClientTransport(
|
||
serverInput: Global.McpClientToServerPipe.Writer.AsStream(),
|
||
serverOutput: Global.McpServerToClientPipe.Reader.AsStream());
|
||
|
||
_mcpClient = await McpClientFactory.CreateAsync(clientTransport);
|
||
}
|
||
|
||
dynamic? mcp = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(message);
|
||
if (mcp == null)
|
||
return string.Empty;
|
||
|
||
JsonNode? root = JsonNode.Parse(message);
|
||
|
||
if (mcp.method == "initialize")
|
||
{
|
||
Global.McpVisionUrl = root?["params"]?["capabilities"]?["vision"]?["url"]?.GetValue<string>();
|
||
Global.McpVisionToken = root?["params"]?["capabilities"]?["vision"]?["token"]?.GetValue<string>();
|
||
|
||
|
||
// 处理初始化请求,构造 Result 数据(非匿名类型,需确保属性名匹配)
|
||
var resultData = new
|
||
{
|
||
protocolVersion = "2024-11-05",
|
||
capabilities = _mcpClient.ServerCapabilities,
|
||
serverInfo = new
|
||
{
|
||
name = "XiaoZhiSharp", // 设备名称 (BOARD_NAME)
|
||
version = Global.CurrentVersion, // 设备固件版本
|
||
}
|
||
};
|
||
|
||
// 直接序列化为 JsonNode(关键步骤)
|
||
JsonNode resultNode = JsonSerializer.SerializeToNode(resultData);
|
||
JsonRpcResponse? response = new JsonRpcResponse()
|
||
{
|
||
Id = new RequestId((long)mcp.id),
|
||
JsonRpc = "2.0",
|
||
Result = resultNode
|
||
};
|
||
|
||
return JsonSerializer.Serialize(response);
|
||
}
|
||
|
||
if (mcp.method == "tools/list")
|
||
{
|
||
// 处理工具列表请求
|
||
var tools = await _mcpClient.ListToolsAsync();
|
||
List<Tool> toolsList = new List<Tool>();
|
||
foreach (var item in tools)
|
||
{
|
||
toolsList.Add(item.ProtocolTool);
|
||
}
|
||
|
||
var resultData = new
|
||
{
|
||
tools = toolsList
|
||
};
|
||
|
||
JsonNode resultNode = JsonSerializer.SerializeToNode(resultData);
|
||
JsonRpcResponse? response = new JsonRpcResponse()
|
||
{
|
||
Id = new RequestId((long)mcp.id),
|
||
JsonRpc = "2.0",
|
||
Result = resultNode
|
||
};
|
||
|
||
var options = new JsonSerializerOptions
|
||
{
|
||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping // 关键配置
|
||
};
|
||
|
||
return JsonSerializer.Serialize(response, options);
|
||
}
|
||
|
||
if (mcp.method == "tools/call")
|
||
{
|
||
// 处理工具调用请求
|
||
//JsonNode? root = JsonNode.Parse(message);
|
||
|
||
// 安全提取 name 和 arguments
|
||
string? name = root?["params"]?["name"]?.GetValue<string>();
|
||
JsonNode? argumentsNode = root?["params"]?["arguments"];
|
||
|
||
// 将 arguments 转换为 Dictionary<string, object>
|
||
Dictionary<string, object>? arguments = null;
|
||
if (argumentsNode != null)
|
||
{
|
||
arguments = argumentsNode.Deserialize<Dictionary<string, object>>();
|
||
}
|
||
|
||
ModelContextProtocol.Protocol.CallToolResult? callToolResponse = await _mcpClient.CallToolAsync(name, arguments);
|
||
JsonNode jsonNode = JsonSerializer.SerializeToNode(callToolResponse);
|
||
JsonRpcResponse? response = new JsonRpcResponse()
|
||
{
|
||
Id = new RequestId((long)mcp.id),
|
||
JsonRpc = "2.0",
|
||
Result = jsonNode
|
||
};
|
||
|
||
var options = new JsonSerializerOptions
|
||
{
|
||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||
};
|
||
return JsonSerializer.Serialize(response, options);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
string errorMessage = $"MCP处理异常: {ex.Message}";
|
||
}
|
||
|
||
return string.Empty;
|
||
}
|
||
}
|
||
} |