mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 10:03:54 +08:00
update:支持中文名称的mcp工具
This commit is contained in:
+44
-17
@@ -5,6 +5,7 @@ import java.net.URISyntaxException;
|
|||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -18,7 +19,6 @@ import xiaozhi.common.utils.AESUtils;
|
|||||||
import xiaozhi.common.utils.HashEncryptionUtil;
|
import xiaozhi.common.utils.HashEncryptionUtil;
|
||||||
import xiaozhi.common.utils.JsonUtils;
|
import xiaozhi.common.utils.JsonUtils;
|
||||||
import xiaozhi.modules.agent.dto.McpJsonRpcRequest;
|
import xiaozhi.modules.agent.dto.McpJsonRpcRequest;
|
||||||
import xiaozhi.modules.agent.dto.McpJsonRpcResponse;
|
|
||||||
import xiaozhi.modules.agent.service.AgentMcpAccessPointService;
|
import xiaozhi.modules.agent.service.AgentMcpAccessPointService;
|
||||||
import xiaozhi.modules.sys.service.SysParamsService;
|
import xiaozhi.modules.sys.service.SysParamsService;
|
||||||
import xiaozhi.modules.sys.utils.WebSocketClientManager;
|
import xiaozhi.modules.sys.utils.WebSocketClientManager;
|
||||||
@@ -66,24 +66,42 @@ public class AgentMcpAccessPointServiceImpl implements AgentMcpAccessPointServic
|
|||||||
new WebSocketClientManager.Builder()
|
new WebSocketClientManager.Builder()
|
||||||
.uri(wsUrl)
|
.uri(wsUrl)
|
||||||
.connectTimeout(5, TimeUnit.SECONDS)
|
.connectTimeout(5, TimeUnit.SECONDS)
|
||||||
.maxSessionDuration(20, TimeUnit.SECONDS))) {
|
.maxSessionDuration(9, TimeUnit.SECONDS))) {
|
||||||
|
|
||||||
// 发送初始化通知
|
// 发送初始化消息
|
||||||
McpJsonRpcRequest initRequest = new McpJsonRpcRequest("notifications/initialized");
|
McpJsonRpcRequest initializeRequest = new McpJsonRpcRequest("initialize",
|
||||||
client.sendJson(initRequest);
|
Map.of(
|
||||||
|
"protocolVersion", "2024-11-05",
|
||||||
|
"capabilities", Map.of(
|
||||||
|
"roots", Map.of("listChanged", false),
|
||||||
|
"sampling", Map.of()),
|
||||||
|
"clientInfo", Map.of(
|
||||||
|
"name", "xz-mcp-broker",
|
||||||
|
"version", "0.0.1")),
|
||||||
|
1);
|
||||||
|
client.sendJson(initializeRequest);
|
||||||
|
|
||||||
|
// 等待初始化响应
|
||||||
|
Thread.sleep(200);
|
||||||
|
|
||||||
|
// 发送初始化完成通知
|
||||||
|
// 对于通知类型的消息,手动构建JSON以避免包含null字段
|
||||||
|
String notificationJson = "{\"jsonrpc\":\"2.0\",\"method\":\"notifications/initialized\"}";
|
||||||
|
client.sendText(notificationJson);
|
||||||
|
|
||||||
// 等待 0.2 秒
|
// 等待 0.2 秒
|
||||||
Thread.sleep(200);
|
Thread.sleep(200);
|
||||||
|
|
||||||
// 发送工具列表请求
|
// 发送工具列表请求
|
||||||
McpJsonRpcRequest toolsRequest = new McpJsonRpcRequest("tools/list", null, 1);
|
McpJsonRpcRequest toolsRequest = new McpJsonRpcRequest("tools/list", null, 2);
|
||||||
client.sendJson(toolsRequest);
|
client.sendJson(toolsRequest);
|
||||||
|
|
||||||
// 监听响应,直到收到包含 id=1 的响应
|
// 监听响应,直到收到包含 id=2 的响应(tools/list响应)
|
||||||
List<String> responses = client.listener(response -> {
|
List<String> responses = client.listener(response -> {
|
||||||
try {
|
try {
|
||||||
McpJsonRpcResponse jsonResponse = JsonUtils.parseObject(response, McpJsonRpcResponse.class);
|
// 先尝试解析为通用JSON对象来获取id
|
||||||
return jsonResponse != null && Integer.valueOf(1).equals(jsonResponse.getId());
|
Map<String, Object> jsonMap = JsonUtils.parseObject(response, Map.class);
|
||||||
|
return jsonMap != null && Integer.valueOf(2).equals(jsonMap.get("id"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("解析响应失败: {}", response, e);
|
log.warn("解析响应失败: {}", response, e);
|
||||||
return false;
|
return false;
|
||||||
@@ -93,14 +111,23 @@ public class AgentMcpAccessPointServiceImpl implements AgentMcpAccessPointServic
|
|||||||
// 处理响应
|
// 处理响应
|
||||||
for (String response : responses) {
|
for (String response : responses) {
|
||||||
try {
|
try {
|
||||||
McpJsonRpcResponse jsonResponse = JsonUtils.parseObject(response, McpJsonRpcResponse.class);
|
// 先解析为通用JSON对象
|
||||||
if (jsonResponse != null && Integer.valueOf(1).equals(jsonResponse.getId())
|
Map<String, Object> jsonMap = JsonUtils.parseObject(response, Map.class);
|
||||||
&& jsonResponse.getResult() != null && jsonResponse.getResult().getTools() != null) {
|
if (jsonMap != null && Integer.valueOf(2).equals(jsonMap.get("id"))) {
|
||||||
|
// 检查是否有result字段
|
||||||
// 提取工具名称列表
|
Object resultObj = jsonMap.get("result");
|
||||||
return java.util.Arrays.stream(jsonResponse.getResult().getTools())
|
if (resultObj instanceof Map) {
|
||||||
.map(McpJsonRpcResponse.McpTool::getName)
|
Map<String, Object> resultMap = (Map<String, Object>) resultObj;
|
||||||
.collect(Collectors.toList());
|
Object toolsObj = resultMap.get("tools");
|
||||||
|
if (toolsObj instanceof List) {
|
||||||
|
List<Map<String, Object>> toolsList = (List<Map<String, Object>>) toolsObj;
|
||||||
|
// 提取工具名称列表
|
||||||
|
return toolsList.stream()
|
||||||
|
.map(tool -> (String) tool.get("name"))
|
||||||
|
.filter(name -> name != null)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("处理工具列表响应失败: {}", response, e);
|
log.warn("处理工具列表响应失败: {}", response, e);
|
||||||
|
|||||||
@@ -980,4 +980,5 @@ def is_valid_image_file(file_data: bytes) -> bool:
|
|||||||
|
|
||||||
def sanitize_tool_name(name: str) -> str:
|
def sanitize_tool_name(name: str) -> str:
|
||||||
"""Sanitize tool names for OpenAI compatibility."""
|
"""Sanitize tool names for OpenAI compatibility."""
|
||||||
return re.sub(r"[^a-zA-Z0-9_-]", "_", name)
|
# 支持中文、英文字母、数字、下划线和连字符
|
||||||
|
return re.sub(r"[^a-zA-Z0-9_\-\u4e00-\u9fff]", "_", name)
|
||||||
|
|||||||
Reference in New Issue
Block a user