2025-10-11 18:25:59 +08:00

149 lines
5.7 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}
}