|
|
|
@ -36,9 +36,11 @@ public class MCPSubClient { |
|
|
|
|
|
|
|
// 使用官方MCP Swift SDK |
|
|
|
private var mcpClient: Client? |
|
|
|
private var transport: CustomSseClientTransport? |
|
|
|
private var tools: [Tool] = [] |
|
|
|
private var toolMaps: [[String: Any]] = [] |
|
|
|
private var isConnectedFlag = false |
|
|
|
private let toolsLock = NSLock() |
|
|
|
|
|
|
|
// 重连配置 |
|
|
|
private let maxRetryAttempts = 3 |
|
|
|
@ -51,6 +53,10 @@ public class MCPSubClient { |
|
|
|
// 工具调用配置 - 添加这两行 |
|
|
|
private let maxToolCallRetries = 3 |
|
|
|
private let toolCallTimeout: TimeInterval = 30.0 |
|
|
|
|
|
|
|
private let keepAliveInterval: TimeInterval = 25.0 |
|
|
|
private let keepAliveTimeout: TimeInterval = 8.0 |
|
|
|
private var keepAliveTask: Task<Void, Never>? |
|
|
|
|
|
|
|
// 连接状态锁 |
|
|
|
private let connectionLock = NSLock() |
|
|
|
@ -89,6 +95,7 @@ public class MCPSubClient { |
|
|
|
} |
|
|
|
} |
|
|
|
) |
|
|
|
self.transport = transport |
|
|
|
|
|
|
|
// 3. 连接到服务器(添加超时) |
|
|
|
try await withTimeout(seconds: 10) { |
|
|
|
@ -106,6 +113,7 @@ public class MCPSubClient { |
|
|
|
isConnectedFlag = true |
|
|
|
retryCount = 0 // 重置重试计数 |
|
|
|
currentReconnectDelay = initialReconnectDelay // 重置延迟 |
|
|
|
startKeepAlive() |
|
|
|
|
|
|
|
return true |
|
|
|
|
|
|
|
@ -116,6 +124,9 @@ public class MCPSubClient { |
|
|
|
} |
|
|
|
|
|
|
|
private func processTools(_ toolList: [Tool]) { |
|
|
|
toolsLock.lock() |
|
|
|
defer { toolsLock.unlock() } |
|
|
|
|
|
|
|
tools.removeAll() |
|
|
|
toolMaps.removeAll() |
|
|
|
|
|
|
|
@ -173,6 +184,13 @@ public class MCPSubClient { |
|
|
|
/// 检查连接状态 |
|
|
|
/// 检查连接状态 |
|
|
|
public func checkConnection() async -> Bool { |
|
|
|
if isConnectedFlag, let transport { |
|
|
|
let isActive = await transport.isConnectionActive() |
|
|
|
if !isActive { |
|
|
|
isConnectedFlag = false |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if !isConnectedFlag { |
|
|
|
return await connect() |
|
|
|
} |
|
|
|
@ -339,14 +357,25 @@ public class MCPSubClient { |
|
|
|
} |
|
|
|
|
|
|
|
public func getToolMaps() -> [[String: Any]] { |
|
|
|
toolsLock.lock() |
|
|
|
defer { toolsLock.unlock() } |
|
|
|
|
|
|
|
return toolMaps |
|
|
|
} |
|
|
|
|
|
|
|
public func containsTool(name: String) -> Bool { |
|
|
|
toolsLock.lock() |
|
|
|
defer { toolsLock.unlock() } |
|
|
|
|
|
|
|
return tools.contains { $0.name == name } |
|
|
|
} |
|
|
|
|
|
|
|
public func close() async { |
|
|
|
keepAliveTask?.cancel() |
|
|
|
keepAliveTask = nil |
|
|
|
reconnectTask?.cancel() |
|
|
|
reconnectTask = nil |
|
|
|
|
|
|
|
if let client = mcpClient { |
|
|
|
await client.disconnect() |
|
|
|
} |
|
|
|
@ -359,9 +388,9 @@ public class MCPSubClient { |
|
|
|
if isConnectedFlag { |
|
|
|
print("[\(serverId)] 连接已断开,更新状态") |
|
|
|
isConnectedFlag = false |
|
|
|
|
|
|
|
// 启动重连逻辑 |
|
|
|
// startReconnection() |
|
|
|
keepAliveTask?.cancel() |
|
|
|
keepAliveTask = nil |
|
|
|
startReconnection() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -369,7 +398,9 @@ public class MCPSubClient { |
|
|
|
/// 启动重连 |
|
|
|
private func startReconnection() { |
|
|
|
// 取消之前的重连任务 |
|
|
|
reconnectTask?.cancel() |
|
|
|
if reconnectTask != nil { |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
reconnectTask = Task { [weak self] in |
|
|
|
await self?.performReconnection() |
|
|
|
@ -378,6 +409,8 @@ public class MCPSubClient { |
|
|
|
|
|
|
|
/// 执行重连 |
|
|
|
private func performReconnection() async { |
|
|
|
defer { reconnectTask = nil } |
|
|
|
|
|
|
|
while retryCount < maxRetryAttempts && !Task.isCancelled { |
|
|
|
retryCount += 1 |
|
|
|
|
|
|
|
@ -403,6 +436,8 @@ public class MCPSubClient { |
|
|
|
private func handleConnectionError(_ error: Error) async { |
|
|
|
print("[\(serverId)] 连接错误: \(error.localizedDescription)") |
|
|
|
isConnectedFlag = false |
|
|
|
keepAliveTask?.cancel() |
|
|
|
keepAliveTask = nil |
|
|
|
|
|
|
|
// 如果是MCP特定错误,可以进行特殊处理 |
|
|
|
if let mcpError = error as? MCPError { |
|
|
|
@ -411,9 +446,49 @@ public class MCPSubClient { |
|
|
|
} |
|
|
|
|
|
|
|
// 如果还有重试机会,启动重连 |
|
|
|
// if retryCount < maxRetryAttempts { |
|
|
|
// startReconnection() |
|
|
|
// } |
|
|
|
startReconnection() |
|
|
|
} |
|
|
|
|
|
|
|
private func startKeepAlive() { |
|
|
|
keepAliveTask?.cancel() |
|
|
|
|
|
|
|
keepAliveTask = Task { [weak self] in |
|
|
|
guard let self else { return } |
|
|
|
|
|
|
|
while !Task.isCancelled { |
|
|
|
try? await Task.sleep(for: .seconds(self.keepAliveInterval)) |
|
|
|
|
|
|
|
if Task.isCancelled { |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
if !self.isConnectedFlag { |
|
|
|
continue |
|
|
|
} |
|
|
|
|
|
|
|
if let transport = self.transport { |
|
|
|
let isActive = await transport.isConnectionActive() |
|
|
|
if !isActive { |
|
|
|
await self.handleConnectionLost() |
|
|
|
continue |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
guard let client = self.mcpClient else { |
|
|
|
await self.handleConnectionError(MCPError.internalError("MCP client not initialized")) |
|
|
|
continue |
|
|
|
} |
|
|
|
|
|
|
|
do { |
|
|
|
let (toolList, _) = try await withTimeout(seconds: self.keepAliveTimeout) { |
|
|
|
try await client.listTools() |
|
|
|
} |
|
|
|
self.processTools(toolList) |
|
|
|
} catch { |
|
|
|
await self.handleConnectionError(error) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 获取连接状态 |
|
|
|
@ -665,7 +740,7 @@ public class MCPClient { |
|
|
|
} |
|
|
|
|
|
|
|
public func isConnected() -> Bool { |
|
|
|
return !subClients.isEmpty && subClients.values.allSatisfy { $0.getConnectionStatus() } |
|
|
|
return !subClients.isEmpty && subClients.values.contains { $0.getConnectionStatus() } |
|
|
|
} |
|
|
|
|
|
|
|
public func disconnectAll() async { |
|
|
|
|