Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Sources/MCP/Base/Error.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import Foundation

#if canImport(System)
import System
#else
@preconcurrency import SystemPackage
#endif

/// A model context protocol error.
public enum Error: Sendable {
// Standard JSON-RPC 2.0 errors (-32700 to -32603)
Expand Down Expand Up @@ -29,6 +35,20 @@ public enum Error: Sendable {
case .transportError: return -32001
}
}

/// Check if an error represents a "resource temporarily unavailable" condition
public static func isResourceTemporarilyUnavailable(_ error: Swift.Error) -> Bool {
#if canImport(System)
if let errno = error as? System.Errno, errno == .resourceTemporarilyUnavailable {
return true
}
#else
if let errno = error as? SystemPackage.Errno, errno == .resourceTemporarilyUnavailable {
return true
}
#endif
return false
}
}

// MARK: LocalizedError
Expand Down
11 changes: 8 additions & 3 deletions Sources/MCP/Base/Transports.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import Darwin
import Logging
import SystemPackage

import struct Foundation.Data

#if canImport(System)
import System
#else
@preconcurrency import SystemPackage
#endif

/// Protocol defining the transport layer for MCP communication
public protocol Transport: Actor {
var logger: Logger { get }
Expand Down Expand Up @@ -107,7 +112,7 @@ public actor StdioTransport: Transport {
messageContinuation.yield(message)
}
}
} catch let error as Errno where error == .resourceTemporarilyUnavailable {
} catch let error where Error.isResourceTemporarilyUnavailable(error) {
try? await Task.sleep(nanoseconds: 10_000_000) // 10ms backoff
continue
} catch {
Expand Down Expand Up @@ -147,7 +152,7 @@ public actor StdioTransport: Transport {
if written > 0 {
remaining = remaining.dropFirst(written)
}
} catch let error as Errno where error == .resourceTemporarilyUnavailable {
} catch let error where Error.isResourceTemporarilyUnavailable(error) {
try await Task.sleep(nanoseconds: 10_000_000) // 10ms backoff
continue
} catch {
Expand Down
3 changes: 1 addition & 2 deletions Sources/MCP/Client/Client.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Logging
import SystemPackage

import struct Foundation.Data
import struct Foundation.Date
Expand Down Expand Up @@ -180,7 +179,7 @@ public actor Client {
"Unexpected message received by client", metadata: metadata)
}
}
} catch let error as Errno where error == .resourceTemporarilyUnavailable {
} catch let error where Error.isResourceTemporarilyUnavailable(error) {
try? await Task.sleep(nanoseconds: 10_000_000) // 10ms
continue
} catch {
Expand Down
3 changes: 1 addition & 2 deletions Sources/MCP/Server/Server.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Logging
import SystemPackage

import struct Foundation.Data
import struct Foundation.Date
Expand Down Expand Up @@ -202,7 +201,7 @@ public actor Server {
}
throw Error.parseError("Invalid message format")
}
} catch let error as Errno where error == .resourceTemporarilyUnavailable {
} catch let error where Error.isResourceTemporarilyUnavailable(error) {
// Resource temporarily unavailable, retry after a short delay
try? await Task.sleep(nanoseconds: 10_000_000) // 10ms
continue
Expand Down
7 changes: 6 additions & 1 deletion Tests/MCPTests/RoundtripTests.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import Foundation
import Logging
import SystemPackage
import Testing

@testable import MCP

#if canImport(System)
import System
#else
@preconcurrency import SystemPackage
#endif

@Suite("Roundtrip Tests")
struct RoundtripTests {
@Test(
Expand Down
7 changes: 6 additions & 1 deletion Tests/MCPTests/TransportTests.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import Foundation
import SystemPackage
import Testing

@testable import MCP

#if canImport(System)
import System
#else
@preconcurrency import SystemPackage
#endif

@Suite("Stdio Transport Tests")
struct StdioTransportTests {
@Test("Connection")
Expand Down