i18n: 全部用户可见字符串统一为英文(46个文件)
- 所有Command/Tool/Core/MCP/Plugin中的中文提示改为英文 - Javadoc注释和行内注释保留中文不变 - AI提示词(compact/commit/review等)改为英文 - 编译验证通过 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -61,8 +61,8 @@ public class McpClient implements AutoCloseable {
|
||||
* @param transport 传输层实现
|
||||
*/
|
||||
public McpClient(String serverName, McpTransport transport) {
|
||||
this.serverName = Objects.requireNonNull(serverName, "服务器名称不能为空");
|
||||
this.transport = Objects.requireNonNull(transport, "传输层不能为空");
|
||||
this.serverName = Objects.requireNonNull(serverName, "Server name cannot be null");
|
||||
this.transport = Objects.requireNonNull(transport, "Transport cannot be null");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,7 +79,7 @@ public class McpClient implements AutoCloseable {
|
||||
* @throws McpException 初始化失败
|
||||
*/
|
||||
public void initialize() throws McpException {
|
||||
log.info("正在初始化 MCP 服务器 '{}'...", serverName);
|
||||
log.info("Initializing MCP server '{}'...", serverName);
|
||||
|
||||
// 1. 发送 initialize 请求
|
||||
int initId = nextId();
|
||||
@@ -101,7 +101,7 @@ public class McpClient implements AutoCloseable {
|
||||
try {
|
||||
response = transport.sendRequest(MAPPER.writeValueAsString(initRequest));
|
||||
} catch (Exception e) {
|
||||
throw new McpException("MCP initialize 请求失败: " + e.getMessage(), e);
|
||||
throw new McpException("MCP initialize request failed: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
// 2. 解析服务器能力
|
||||
@@ -111,9 +111,9 @@ public class McpClient implements AutoCloseable {
|
||||
serverInfo = result.get("serverInfo");
|
||||
String serverVersion = result.has("protocolVersion")
|
||||
? result.get("protocolVersion").asText() : "unknown";
|
||||
log.info("MCP 服务器 '{}' 协议版本: {}", serverName, serverVersion);
|
||||
log.info("MCP server '{}' protocol version: {}", serverName, serverVersion);
|
||||
if (serverInfo != null) {
|
||||
log.info("MCP 服务器信息: {}", serverInfo);
|
||||
log.info("MCP server info: {}", serverInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ public class McpClient implements AutoCloseable {
|
||||
try {
|
||||
transport.sendNotification(MAPPER.writeValueAsString(initializedNotif));
|
||||
} catch (Exception e) {
|
||||
throw new McpException("发送 initialized 通知失败: " + e.getMessage(), e);
|
||||
throw new McpException("Failed to send initialized notification: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
// 4. 发现工具
|
||||
@@ -135,7 +135,7 @@ public class McpClient implements AutoCloseable {
|
||||
discoverResources();
|
||||
|
||||
initialized = true;
|
||||
log.info("MCP 服务器 '{}' 初始化完成: {} 个工具, {} 个资源",
|
||||
log.info("MCP server '{}' initialization complete: {} tools, {} resources",
|
||||
serverName, tools.size(), resources.size());
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ public class McpClient implements AutoCloseable {
|
||||
&& serverCapabilities.get("tools").isObject()) {
|
||||
// 服务器声明支持工具
|
||||
} else if (serverCapabilities != null && !serverCapabilities.has("tools")) {
|
||||
log.debug("MCP 服务器 '{}' 未声明 tools 能力,尝试发现工具", serverName);
|
||||
log.debug("MCP server '{}' did not declare tools capability, attempting discovery", serverName);
|
||||
}
|
||||
|
||||
int id = nextId();
|
||||
@@ -173,19 +173,19 @@ public class McpClient implements AutoCloseable {
|
||||
JsonNode inputSchema = toolNode.get("inputSchema");
|
||||
|
||||
tools.put(name, new McpTool(name, description, inputSchema));
|
||||
log.debug("发现 MCP 工具: {} - {}", name, description);
|
||||
log.debug("Discovered MCP tool: {} - {}", name, description);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (McpException e) {
|
||||
// tools/list 可能不被支持,记录警告但不中断初始化
|
||||
if (e.isJsonRpcError() && e.getErrorCode() == -32601) {
|
||||
log.debug("MCP 服务器 '{}' 不支持 tools/list", serverName);
|
||||
log.debug("MCP server '{}' does not support tools/list", serverName);
|
||||
} else {
|
||||
log.warn("发现 MCP 工具失败: {}", e.getMessage());
|
||||
log.warn("Failed to discover MCP tools: {}", e.getMessage());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("发现 MCP 工具时序列化异常: {}", e.getMessage());
|
||||
log.warn("MCP tool discovery serialization exception: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ public class McpClient implements AutoCloseable {
|
||||
&& serverCapabilities.get("resources").isObject()) {
|
||||
// 服务器声明支持资源
|
||||
} else if (serverCapabilities != null && !serverCapabilities.has("resources")) {
|
||||
log.debug("MCP 服务器 '{}' 未声明 resources 能力,跳过资源发现", serverName);
|
||||
log.debug("MCP server '{}' did not declare resources capability, skipping discovery", serverName);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -226,18 +226,18 @@ public class McpClient implements AutoCloseable {
|
||||
? resNode.get("mimeType").asText() : "text/plain";
|
||||
|
||||
resources.put(uri, new McpResource(uri, name, description, mimeType));
|
||||
log.debug("发现 MCP 资源: {} ({})", name, uri);
|
||||
log.debug("Discovered MCP resource: {} ({})", name, uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (McpException e) {
|
||||
if (e.isJsonRpcError() && e.getErrorCode() == -32601) {
|
||||
log.debug("MCP 服务器 '{}' 不支持 resources/list", serverName);
|
||||
log.debug("MCP server '{}' does not support resources/list", serverName);
|
||||
} else {
|
||||
log.warn("发现 MCP 资源失败: {}", e.getMessage());
|
||||
log.warn("Failed to discover MCP resources: {}", e.getMessage());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("发现 MCP 资源时序列化异常: {}", e.getMessage());
|
||||
log.warn("MCP resource discovery serialization exception: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,10 +251,10 @@ public class McpClient implements AutoCloseable {
|
||||
*/
|
||||
public String callTool(String toolName, Map<String, Object> arguments) throws McpException {
|
||||
if (!initialized) {
|
||||
throw new McpException("MCP 客户端尚未初始化");
|
||||
throw new McpException("MCP client not yet initialized");
|
||||
}
|
||||
if (!tools.containsKey(toolName)) {
|
||||
throw new McpException("MCP 工具不存在: " + toolName);
|
||||
throw new McpException("MCP tool does not exist: " + toolName);
|
||||
}
|
||||
|
||||
int id = nextId();
|
||||
@@ -269,7 +269,7 @@ public class McpClient implements AutoCloseable {
|
||||
);
|
||||
|
||||
try {
|
||||
log.debug("调用 MCP 工具: {} (参数: {})", toolName, arguments);
|
||||
log.debug("Calling MCP tool: {} (args: {})", toolName, arguments);
|
||||
JsonNode response = transport.sendRequest(MAPPER.writeValueAsString(request));
|
||||
JsonNode result = response.get("result");
|
||||
|
||||
@@ -292,7 +292,7 @@ public class McpClient implements AutoCloseable {
|
||||
|
||||
// 检查 isError 标志
|
||||
if (result.has("isError") && result.get("isError").asBoolean()) {
|
||||
throw new McpException("MCP 工具 '" + toolName + "' 执行出错: " + sb);
|
||||
throw new McpException("MCP tool '" + toolName + "' execution error: " + sb);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
@@ -304,7 +304,7 @@ public class McpClient implements AutoCloseable {
|
||||
} catch (McpException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new McpException("调用 MCP 工具 '" + toolName + "' 失败: " + e.getMessage(), e);
|
||||
throw new McpException("Failed to call MCP tool '" + toolName + "': " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ public class McpClient implements AutoCloseable {
|
||||
*/
|
||||
public String readResource(String uri) throws McpException {
|
||||
if (!initialized) {
|
||||
throw new McpException("MCP 客户端尚未初始化");
|
||||
throw new McpException("MCP client not yet initialized");
|
||||
}
|
||||
|
||||
int id = nextId();
|
||||
@@ -329,7 +329,7 @@ public class McpClient implements AutoCloseable {
|
||||
);
|
||||
|
||||
try {
|
||||
log.debug("读取 MCP 资源: {}", uri);
|
||||
log.debug("Reading MCP resource: {}", uri);
|
||||
JsonNode response = transport.sendRequest(MAPPER.writeValueAsString(request));
|
||||
JsonNode result = response.get("result");
|
||||
|
||||
@@ -356,7 +356,7 @@ public class McpClient implements AutoCloseable {
|
||||
} catch (McpException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new McpException("读取 MCP 资源 '" + uri + "' 失败: " + e.getMessage(), e);
|
||||
throw new McpException("Failed to read MCP resource '" + uri + "': " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,7 +415,7 @@ public class McpClient implements AutoCloseable {
|
||||
tools.clear();
|
||||
resources.clear();
|
||||
transport.close();
|
||||
log.info("MCP 客户端 '{}' 已关闭", serverName);
|
||||
log.info("MCP client '{}' closed", serverName);
|
||||
}
|
||||
|
||||
/** 生成下一个 JSON-RPC 请求 ID */
|
||||
|
||||
@@ -69,17 +69,17 @@ public class McpManager implements AutoCloseable {
|
||||
// 项目级配置
|
||||
Path projectConfig = Path.of(System.getProperty("user.dir"), PROJECT_CONFIG);
|
||||
if (Files.exists(projectConfig)) {
|
||||
loadConfigFile(projectConfig, "项目级");
|
||||
loadConfigFile(projectConfig, "project");
|
||||
}
|
||||
|
||||
// 全局配置
|
||||
Path globalConfig = Path.of(System.getProperty("user.home"), GLOBAL_CONFIG);
|
||||
if (Files.exists(globalConfig)) {
|
||||
loadConfigFile(globalConfig, "全局");
|
||||
loadConfigFile(globalConfig, "global");
|
||||
}
|
||||
|
||||
if (clients.isEmpty()) {
|
||||
log.debug("未找到 MCP 配置文件或无服务器定义");
|
||||
log.debug("No MCP config file found or no server definitions");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ public class McpManager implements AutoCloseable {
|
||||
* 加载单个配置文件中的 MCP 服务器定义。
|
||||
*/
|
||||
private void loadConfigFile(Path configPath, String label) {
|
||||
log.info("加载 {} MCP 配置: {}", label, configPath);
|
||||
log.info("Loading {} MCP config: {}", label, configPath);
|
||||
|
||||
try {
|
||||
String content = Files.readString(configPath);
|
||||
@@ -95,7 +95,7 @@ public class McpManager implements AutoCloseable {
|
||||
|
||||
JsonNode serversNode = root.get("servers");
|
||||
if (serversNode == null || !serversNode.isObject()) {
|
||||
log.warn("{} 配置文件缺少 'servers' 字段: {}", label, configPath);
|
||||
log.warn("{} config file missing 'servers' field: {}", label, configPath);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ public class McpManager implements AutoCloseable {
|
||||
|
||||
// 跳过已存在的服务器(项目级优先于全局)
|
||||
if (clients.containsKey(name)) {
|
||||
log.debug("MCP 服务器 '{}' 已连接,跳过 {} 配置中的重复定义", name, label);
|
||||
log.debug("MCP server '{}' already connected, skipping duplicate definition in {} config", name, label);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -132,11 +132,11 @@ public class McpManager implements AutoCloseable {
|
||||
|
||||
connect(name, command, args, env);
|
||||
} catch (Exception e) {
|
||||
log.error("从配置连接 MCP 服务器 '{}' 失败: {}", name, e.getMessage());
|
||||
log.error("Failed to connect MCP server '{}' from config: {}", name, e.getMessage());
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("读取 MCP 配置文件失败: {}", configPath, e);
|
||||
log.error("Failed to read MCP config file: {}", configPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,15 +154,15 @@ public class McpManager implements AutoCloseable {
|
||||
throws McpException {
|
||||
// 如果已存在,先断开
|
||||
if (clients.containsKey(name)) {
|
||||
log.info("MCP 服务器 '{}' 已存在,先断开旧连接", name);
|
||||
log.info("MCP server '{}' already exists, disconnecting old connection", name);
|
||||
try {
|
||||
disconnect(name);
|
||||
} catch (Exception e) {
|
||||
log.warn("断开旧 MCP 连接 '{}' 时异常: {}", name, e.getMessage());
|
||||
log.warn("Exception disconnecting old MCP connection '{}': {}", name, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
log.info("连接 MCP 服务器 '{}': {} {}", name, command, String.join(" ", args));
|
||||
log.info("Connecting MCP server '{}': {} {}", name, command, String.join(" ", args));
|
||||
|
||||
// 创建传输层并启动(确保初始化失败时清理资源)
|
||||
StdioTransport transport = new StdioTransport(command, args, env);
|
||||
@@ -179,7 +179,7 @@ public class McpManager implements AutoCloseable {
|
||||
e.addSuppressed(suppressed);
|
||||
}
|
||||
throw (e instanceof McpException mcp) ? mcp
|
||||
: new McpException("连接 MCP 服务器 '" + name + "' 失败: " + e.getMessage(), e);
|
||||
: new McpException("Failed to connect MCP server '" + name + "': " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
// 注册客户端
|
||||
@@ -189,13 +189,13 @@ public class McpManager implements AutoCloseable {
|
||||
for (McpClient.McpTool tool : client.getTools()) {
|
||||
String existingServer = toolToServer.get(tool.name());
|
||||
if (existingServer != null) {
|
||||
log.warn("MCP 工具名称冲突: '{}' 同时存在于服务器 '{}' 和 '{}',使用后者",
|
||||
log.warn("MCP tool name conflict: '{}' exists in both server '{}' and '{}', using latter",
|
||||
tool.name(), existingServer, name);
|
||||
}
|
||||
toolToServer.put(tool.name(), name);
|
||||
}
|
||||
|
||||
log.info("MCP 服务器 '{}' 连接成功", name);
|
||||
log.info("MCP server '{}' connected successfully", name);
|
||||
return client;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ public class McpManager implements AutoCloseable {
|
||||
public void disconnect(String name) throws McpException {
|
||||
McpClient client = clients.remove(name);
|
||||
if (client == null) {
|
||||
throw new McpException("MCP 服务器 '" + name + "' 不存在");
|
||||
throw new McpException("MCP server '" + name + "' does not exist");
|
||||
}
|
||||
|
||||
// 清理工具映射
|
||||
@@ -216,9 +216,9 @@ public class McpManager implements AutoCloseable {
|
||||
|
||||
try {
|
||||
client.close();
|
||||
log.info("MCP 服务器 '{}' 已断开", name);
|
||||
log.info("MCP server '{}' disconnected", name);
|
||||
} catch (Exception e) {
|
||||
throw new McpException("断开 MCP 服务器 '" + name + "' 时异常: " + e.getMessage(), e);
|
||||
throw new McpException("Exception disconnecting MCP server '" + name + "': " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ public class McpManager implements AutoCloseable {
|
||||
public String callTool(String toolName, Map<String, Object> args) throws McpException {
|
||||
String serverName = toolToServer.get(toolName);
|
||||
if (serverName == null) {
|
||||
throw new McpException("未找到 MCP 工具: " + toolName);
|
||||
throw new McpException("MCP tool not found: " + toolName);
|
||||
}
|
||||
return callTool(serverName, toolName, args);
|
||||
}
|
||||
@@ -320,10 +320,10 @@ public class McpManager implements AutoCloseable {
|
||||
throws McpException {
|
||||
McpClient client = clients.get(serverName);
|
||||
if (client == null) {
|
||||
throw new McpException("MCP 服务器 '" + serverName + "' 不存在");
|
||||
throw new McpException("MCP server '" + serverName + "' does not exist");
|
||||
}
|
||||
if (!client.isInitialized()) {
|
||||
throw new McpException("MCP 服务器 '" + serverName + "' 尚未初始化");
|
||||
throw new McpException("MCP server '" + serverName + "' not yet initialized");
|
||||
}
|
||||
return client.callTool(toolName, args);
|
||||
}
|
||||
@@ -344,7 +344,7 @@ public class McpManager implements AutoCloseable {
|
||||
* 先断开所有已有连接,再重新加载配置。
|
||||
*/
|
||||
public void reload() {
|
||||
log.info("重新加载 MCP 配置...");
|
||||
log.info("Reloading MCP config...");
|
||||
|
||||
// 断开所有现有连接
|
||||
List<String> serverNames = new ArrayList<>(clients.keySet());
|
||||
@@ -352,13 +352,13 @@ public class McpManager implements AutoCloseable {
|
||||
try {
|
||||
disconnect(name);
|
||||
} catch (Exception e) {
|
||||
log.warn("重载时断开 MCP 服务器 '{}' 失败: {}", name, e.getMessage());
|
||||
log.warn("Failed to disconnect MCP server '{}' during reload: {}", name, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 重新加载
|
||||
loadFromConfig();
|
||||
log.info("MCP 配置重载完成: {} 个服务器已连接", clients.size());
|
||||
log.info("MCP config reload complete: {} servers connected", clients.size());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,7 +368,7 @@ public class McpManager implements AutoCloseable {
|
||||
*/
|
||||
public String getSummary() {
|
||||
if (clients.isEmpty()) {
|
||||
return " 无已连接的 MCP 服务器";
|
||||
return " No connected MCP servers";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -378,14 +378,14 @@ public class McpManager implements AutoCloseable {
|
||||
|
||||
String status;
|
||||
if (client.isConnected() && client.isInitialized()) {
|
||||
status = "✅ 已连接";
|
||||
status = "✅ Connected";
|
||||
} else if (client.isConnected()) {
|
||||
status = "🔄 连接中";
|
||||
status = "🔄 Connecting";
|
||||
} else {
|
||||
status = "❌ 已断开";
|
||||
status = "❌ Disconnected";
|
||||
}
|
||||
|
||||
sb.append(String.format(" %-20s %s (%d 工具, %d 资源)%n",
|
||||
sb.append(String.format(" %-20s %s (%d tools, %d resources)%n",
|
||||
name, status, client.getTools().size(), client.getResources().size()));
|
||||
}
|
||||
return sb.toString().stripTrailing();
|
||||
@@ -393,7 +393,7 @@ public class McpManager implements AutoCloseable {
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
log.info("关闭所有 MCP 连接...");
|
||||
log.info("Closing all MCP connections...");
|
||||
List<Exception> errors = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<String, McpClient> entry : clients.entrySet()) {
|
||||
@@ -401,18 +401,18 @@ public class McpManager implements AutoCloseable {
|
||||
entry.getValue().close();
|
||||
} catch (Exception e) {
|
||||
errors.add(e);
|
||||
log.error("关闭 MCP 服务器 '{}' 时异常: {}", entry.getKey(), e.getMessage());
|
||||
log.error("Exception closing MCP server '{}': {}", entry.getKey(), e.getMessage());
|
||||
}
|
||||
}
|
||||
clients.clear();
|
||||
toolToServer.clear();
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
McpException ex = new McpException("关闭 MCP 管理器时有 " + errors.size() + " 个错误");
|
||||
McpException ex = new McpException("Errors closing MCP manager: " + errors.size() + " errors");
|
||||
errors.forEach(ex::addSuppressed);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
log.info("所有 MCP 连接已关闭");
|
||||
log.info("All MCP connections closed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ public class StdioTransport implements McpTransport {
|
||||
cmdList.add(command);
|
||||
cmdList.addAll(args);
|
||||
|
||||
log.info("启动 MCP 服务器进程: {}", String.join(" ", cmdList));
|
||||
log.info("Starting MCP server process: {}", String.join(" ", cmdList));
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(cmdList);
|
||||
pb.redirectErrorStream(false); // stderr 单独处理
|
||||
@@ -108,10 +108,10 @@ public class StdioTransport implements McpTransport {
|
||||
stderrThread = Thread.ofVirtual().name("mcp-stdio-stderr").start(this::stderrLoop);
|
||||
|
||||
connected = true;
|
||||
log.info("MCP 服务器进程已启动 (PID: {})", process.pid());
|
||||
log.info("MCP server process started (PID: {})", process.pid());
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new McpException("启动 MCP 服务器进程失败: " + e.getMessage(), e);
|
||||
throw new McpException("Failed to start MCP server process: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,18 +133,18 @@ public class StdioTransport implements McpTransport {
|
||||
JsonNode message = MAPPER.readTree(line);
|
||||
handleMessage(message);
|
||||
} catch (Exception e) {
|
||||
log.warn("解析 MCP 响应失败: {}", line, e);
|
||||
log.warn("Failed to parse MCP response: {}", line, e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (connected) {
|
||||
log.warn("MCP stdout 读取中断: {}", e.getMessage());
|
||||
log.warn("MCP stdout read interrupted: {}", e.getMessage());
|
||||
}
|
||||
} finally {
|
||||
connected = false;
|
||||
// 清理所有等待中的请求
|
||||
pendingRequests.forEach((id, future) ->
|
||||
future.completeExceptionally(new McpException("MCP 连接已断开")));
|
||||
future.completeExceptionally(new McpException("MCP connection disconnected")));
|
||||
pendingRequests.clear();
|
||||
}
|
||||
}
|
||||
@@ -182,19 +182,19 @@ public class StdioTransport implements McpTransport {
|
||||
if (future != null) {
|
||||
future.complete(message);
|
||||
} else {
|
||||
log.warn("收到未匹配的 MCP 响应 (id={}): {}", id, message);
|
||||
log.warn("Received unmatched MCP response (id={}): {}", id, message);
|
||||
}
|
||||
} else {
|
||||
// 服务器主动通知(如 notifications/tools/list_changed)
|
||||
String method = message.has("method") ? message.get("method").asText() : "unknown";
|
||||
log.debug("收到 MCP 服务器通知: {}", method);
|
||||
log.debug("Received MCP server notification: {}", method);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode sendRequest(String jsonRpcRequest) throws McpException {
|
||||
if (!connected) {
|
||||
throw new McpException("MCP 传输层未连接");
|
||||
throw new McpException("MCP transport not connected");
|
||||
}
|
||||
|
||||
String id = null;
|
||||
@@ -203,7 +203,7 @@ public class StdioTransport implements McpTransport {
|
||||
JsonNode requestNode = MAPPER.readTree(jsonRpcRequest);
|
||||
JsonNode idNode = requestNode.get("id");
|
||||
if (idNode == null || idNode.isNull()) {
|
||||
throw new McpException("JSON-RPC 请求缺少 id 字段");
|
||||
throw new McpException("JSON-RPC request missing id field");
|
||||
}
|
||||
id = idNode.asText();
|
||||
|
||||
@@ -218,7 +218,7 @@ public class StdioTransport implements McpTransport {
|
||||
processStdin.flush();
|
||||
}
|
||||
|
||||
log.debug("发送 MCP 请求 (id={}): {}", id, truncate(jsonRpcRequest, 200));
|
||||
log.debug("Sent MCP request (id={}): {}", id, truncate(jsonRpcRequest, 200));
|
||||
|
||||
// 等待响应
|
||||
JsonNode response = future.get(DEFAULT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
@@ -227,8 +227,8 @@ public class StdioTransport implements McpTransport {
|
||||
JsonNode errorNode = response.get("error");
|
||||
if (errorNode != null && !errorNode.isNull()) {
|
||||
int code = errorNode.has("code") ? errorNode.get("code").asInt() : -1;
|
||||
String msg = errorNode.has("message") ? errorNode.get("message").asText() : "未知错误";
|
||||
throw new McpException("MCP 服务器返回错误: " + msg, code);
|
||||
String msg = errorNode.has("message") ? errorNode.get("message").asText() : "Unknown error";
|
||||
throw new McpException("MCP server returned error: " + msg, code);
|
||||
}
|
||||
|
||||
return response;
|
||||
@@ -236,15 +236,15 @@ public class StdioTransport implements McpTransport {
|
||||
} catch (McpException e) {
|
||||
throw e;
|
||||
} catch (TimeoutException e) {
|
||||
throw new McpException("MCP 请求超时 (" + DEFAULT_TIMEOUT_SECONDS + "s)", e);
|
||||
throw new McpException("MCP request timeout (" + DEFAULT_TIMEOUT_SECONDS + "s)", e);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof McpException mcp) {
|
||||
throw mcp;
|
||||
}
|
||||
throw new McpException("MCP 请求执行异常: " + cause.getMessage(), cause);
|
||||
throw new McpException("MCP request execution exception: " + cause.getMessage(), cause);
|
||||
} catch (Exception e) {
|
||||
throw new McpException("MCP 请求发送失败: " + e.getMessage(), e);
|
||||
throw new McpException("MCP request send failed: " + e.getMessage(), e);
|
||||
} finally {
|
||||
// 无论成功、超时或异常,都清理待处理请求,防止内存泄漏
|
||||
if (id != null) {
|
||||
@@ -256,7 +256,7 @@ public class StdioTransport implements McpTransport {
|
||||
@Override
|
||||
public void sendNotification(String jsonRpcNotification) throws McpException {
|
||||
if (!connected) {
|
||||
throw new McpException("MCP 传输层未连接");
|
||||
throw new McpException("MCP transport not connected");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -265,9 +265,9 @@ public class StdioTransport implements McpTransport {
|
||||
processStdin.newLine();
|
||||
processStdin.flush();
|
||||
}
|
||||
log.debug("发送 MCP 通知: {}", truncate(jsonRpcNotification, 200));
|
||||
log.debug("Sent MCP notification: {}", truncate(jsonRpcNotification, 200));
|
||||
} catch (IOException e) {
|
||||
throw new McpException("MCP 通知发送失败: " + e.getMessage(), e);
|
||||
throw new McpException("MCP notification send failed: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,14 +279,14 @@ public class StdioTransport implements McpTransport {
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
connected = false;
|
||||
log.info("关闭 MCP StdIO 传输...");
|
||||
log.info("Closing MCP StdIO transport...");
|
||||
|
||||
// 关闭 stdin(通知服务器退出)
|
||||
if (processStdin != null) {
|
||||
try {
|
||||
processStdin.close();
|
||||
} catch (IOException e) {
|
||||
log.debug("关闭 stdin 时异常: {}", e.getMessage());
|
||||
log.debug("Exception closing stdin: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ public class StdioTransport implements McpTransport {
|
||||
if (process != null && process.isAlive()) {
|
||||
boolean exited = process.waitFor(5, TimeUnit.SECONDS);
|
||||
if (!exited) {
|
||||
log.warn("MCP 服务器进程未在 5s 内退出,强制终止");
|
||||
log.warn("MCP server process did not exit within 5s, force terminating");
|
||||
process.destroyForcibly();
|
||||
process.waitFor(3, TimeUnit.SECONDS);
|
||||
}
|
||||
@@ -310,10 +310,10 @@ public class StdioTransport implements McpTransport {
|
||||
|
||||
// 清理待处理请求
|
||||
pendingRequests.forEach((id, future) ->
|
||||
future.completeExceptionally(new McpException("MCP 传输已关闭")));
|
||||
future.completeExceptionally(new McpException("MCP transport closed")));
|
||||
pendingRequests.clear();
|
||||
|
||||
log.info("MCP StdIO 传输已关闭");
|
||||
log.info("MCP StdIO transport closed");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user