Skip to content

Commit 6136a41

Browse files
madisonrickertsciencemanxclaude
authored
Bump MCP Swift SDK to 0.12.0 and fix connection crash (#162)
* Fix SIGTRAP crash from continuation misuse in connection handling The MCP SDK's NetworkTransport has reconnection logic that creates unstructured tasks holding CheckedContinuation references. For server-side incoming connections, this reconnection path can cause double-resume when connections are cancelled, crashing the app. Disable reconnection and heartbeats for server-accepted connections since they are client features — if a client disconnects, it should reconnect itself. Also make removeConnection idempotent to prevent stop() being called twice on the same connection. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Bump MCP Swift SDK to 0.12.0 and fix breaking API changes Update swift-sdk dependency from revision pin (106167b) to version-based 0.12.0, which resolves Swift 6 strict concurrency data race errors in NetworkTransport that prevented building. Adapt ServerController to the new Tool.Content labeled enum cases and convert inputSchema from JSONSchema to Value at the MCP.Tool creation boundary. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Adam Van Prooyen <adam.vanpr@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 15a540d commit 6136a41

3 files changed

Lines changed: 46 additions & 12 deletions

File tree

App/Controllers/ServerController.swift

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,8 @@ actor MCPConnectionManager {
432432
self.transport = NetworkTransport(
433433
connection: connection,
434434
logger: nil,
435+
heartbeatConfig: .init(enabled: false),
436+
reconnectionConfig: .disabled,
435437
bufferConfig: .unlimited
436438
)
437439

@@ -627,6 +629,7 @@ actor ServerNetworkManager {
627629
private var connections: [UUID: MCPConnectionManager] = [:]
628630
private var connectionTasks: [UUID: Task<Void, Never>] = [:]
629631
private var pendingConnections: [UUID: String] = [:]
632+
private var removedConnections: Set<UUID> = []
630633

631634
typealias ConnectionApprovalHandler = @Sendable (UUID, MCP.Client.Info) async -> Bool
632635
private var connectionApprovalHandler: ConnectionApprovalHandler?
@@ -764,11 +767,20 @@ actor ServerNetworkManager {
764767
connections.removeAll()
765768
connectionTasks.removeAll()
766769
pendingConnections.removeAll()
770+
removedConnections.removeAll()
767771

768772
await discoveryManager?.stop()
769773
}
770774

771775
func removeConnection(_ id: UUID) async {
776+
// Guard against redundant removal — calling stop() on an already-stopped
777+
// connection can trigger a double-resume in the SDK's transport continuation.
778+
guard !removedConnections.contains(id) else {
779+
log.debug("Connection \(id) already removed, skipping")
780+
return
781+
}
782+
removedConnections.insert(id)
783+
772784
log.debug("Removing connection: \(id)")
773785

774786
if let connectionManager = connections[id] {
@@ -873,7 +885,7 @@ actor ServerNetworkManager {
873885
.init(
874886
name: tool.name,
875887
description: tool.description,
876-
inputSchema: tool.inputSchema,
888+
inputSchema: try Value(tool.inputSchema),
877889
annotations: tool.annotations
878890
)
879891
)
@@ -889,7 +901,7 @@ actor ServerNetworkManager {
889901
await server.withMethodHandler(CallTool.self) { [weak self] params in
890902
guard let self = self else {
891903
return CallTool.Result(
892-
content: [.text("Server unavailable")],
904+
content: [.text(text: "Server unavailable", annotations: nil, _meta: nil)],
893905
isError: true
894906
)
895907
}
@@ -899,7 +911,7 @@ actor ServerNetworkManager {
899911
guard await self.isEnabledState else {
900912
log.notice("Tool call rejected: iMCP is disabled")
901913
return CallTool.Result(
902-
content: [.text("iMCP is currently disabled. Please enable it to use tools.")],
914+
content: [.text(text: "iMCP is currently disabled. Please enable it to use tools.", annotations: nil, _meta: nil)],
903915
isError: true
904916
)
905917
}
@@ -928,7 +940,9 @@ actor ServerNetworkManager {
928940
content: [
929941
.audio(
930942
data: data.base64EncodedString(),
931-
mimeType: mimeType
943+
mimeType: mimeType,
944+
annotations: nil,
945+
_meta: nil
932946
)
933947
],
934948
isError: false
@@ -939,7 +953,8 @@ actor ServerNetworkManager {
939953
.image(
940954
data: data.base64EncodedString(),
941955
mimeType: mimeType,
942-
metadata: nil
956+
annotations: nil,
957+
_meta: nil
943958
)
944959
],
945960
isError: false
@@ -953,20 +968,20 @@ actor ServerNetworkManager {
953968
let data = try encoder.encode(value)
954969
let text = String(data: data, encoding: .utf8)!
955970

956-
return CallTool.Result(content: [.text(text)], isError: false)
971+
return CallTool.Result(content: [.text(text: text, annotations: nil, _meta: nil)], isError: false)
957972
}
958973
} catch {
959974
log.error(
960975
"Error executing tool \(params.name): \(error.localizedDescription)"
961976
)
962-
return CallTool.Result(content: [.text("Error: \(error)")], isError: true)
977+
return CallTool.Result(content: [.text(text: "Error: \(error)", annotations: nil, _meta: nil)], isError: true)
963978
}
964979
}
965980
}
966981

967982
log.error("Tool not found or service not enabled: \(params.name)")
968983
return CallTool.Result(
969-
content: [.text("Tool not found or service not enabled: \(params.name)")],
984+
content: [.text(text: "Tool not found or service not enabled: \(params.name)", annotations: nil, _meta: nil)],
970985
isError: true
971986
)
972987
}

iMCP.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -759,8 +759,8 @@
759759
isa = XCRemoteSwiftPackageReference;
760760
repositoryURL = "https://github.com/modelcontextprotocol/swift-sdk";
761761
requirement = {
762-
kind = revision;
763-
revision = 106167bad12cd8d004b0cbfcec8211c5408794d8;
762+
kind = upToNextMinorVersion;
763+
minimumVersion = 0.12.0;
764764
};
765765
};
766766
F8D8C48C2DCE0E6800369E5C /* XCRemoteSwiftPackageReference "JSONSchema" */ = {

iMCP.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 21 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)