Skip to content

Commit 3a9a06c

Browse files
cyberpapiiiclaude
andcommitted
fix: revert server lifecycle to background Task pattern
The runServiceClosure/runService() pattern from the graceful shutdown agent caused SWIFT TASK CONTINUATION MISUSE crashes. Reverted to starting Hummingbird in a background Task within connect() and using withCheckedContinuation in main.swift to keep the process alive. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c8f89f5 commit 3a9a06c

File tree

2 files changed

+11
-17
lines changed

2 files changed

+11
-17
lines changed

swift/Sources/iMessageMax/Server/HTTPTransport.swift

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ public actor HTTPTransport: Transport {
3737
// Request correlation: maps JSON-RPC id to continuation for response
3838
private var pendingRequests: [String: PendingRequest] = [:]
3939

40-
// Closure to run the Hummingbird application with graceful shutdown
41-
private var runServiceClosure: (@Sendable () async throws -> Void)?
40+
/// Background task running the Hummingbird server
41+
private var serverTask: Task<Void, Error>?
4242

4343
/// Tracks a pending request with its session
4444
private struct PendingRequest {
@@ -122,19 +122,10 @@ public actor HTTPTransport: Transport {
122122

123123
isConnected = true
124124

125-
// Store runService closure for lifecycle management
126-
self.runServiceClosure = { try await app.runService() }
127-
}
128-
129-
/// Runs the HTTP server with graceful shutdown support
130-
///
131-
/// This method blocks until the server is shut down via SIGTERM or SIGINT.
132-
/// Uses Hummingbird's built-in ServiceGroup for lifecycle management.
133-
public func runService() async throws {
134-
guard let runService = self.runServiceClosure else {
135-
throw MCPError.serverError(code: -32000, message: "Call connect() before runService()")
125+
// Start the server in a background task
126+
self.serverTask = Task {
127+
try await app.runService()
136128
}
137-
try await runService()
138129
}
139130

140131
/// Handles POST requests with JSON-RPC messages
@@ -446,8 +437,9 @@ public actor HTTPTransport: Transport {
446437
guard isConnected else { return }
447438
isConnected = false
448439

449-
// Clear run closure reference
450-
runServiceClosure = nil
440+
// Cancel server task
441+
serverTask?.cancel()
442+
serverTask = nil
451443

452444
// Terminate all sessions
453445
for sessionId in await sessionManager.activeSessionIds() {

swift/Sources/iMessageMax/main.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ struct iMessageMax: AsyncParsableCommand {
5656
)
5757

5858
try await transport.connect()
59-
try await transport.runService()
59+
await withCheckedContinuation { (_: CheckedContinuation<Void, Never>) in
60+
// Server runs indefinitely until process is terminated
61+
}
6062
} else {
6163
// Stdio mode: Single Server instance managed by MCPServerWrapper
6264
let server = MCPServerWrapper()

0 commit comments

Comments
 (0)