@@ -9,59 +9,61 @@ import struct Foundation.Data
99#endif
1010
1111// Import for specific low-level operations not yet in Swift System
12- #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS )
12+ #if canImport(Darwin )
1313 import Darwin. POSIX
14- #elseif os(Linux )
14+ #elseif canImport(Glibc )
1515 import Glibc
16+ #elseif canImport(Musl)
17+ import Musl
1618#endif
1719
18- /// Standard input/output transport implementation
19- public actor StdioTransport : Transport {
20- private let input : FileDescriptor
21- private let output : FileDescriptor
22- public nonisolated let logger : Logger
23-
24- private var isConnected = false
25- private let messageStream : AsyncStream < Data >
26- private let messageContinuation : AsyncStream < Data > . Continuation
27-
28- public init (
29- input: FileDescriptor = FileDescriptor . standardInput,
30- output: FileDescriptor = FileDescriptor . standardOutput,
31- logger: Logger ? = nil
32- ) {
33- self . input = input
34- self . output = output
35- self . logger =
36- logger
37- ?? Logger (
38- label: " mcp.transport.stdio " ,
39- factory: { _ in SwiftLogNoOpLogHandler ( ) } )
40-
41- // Create message stream
42- var continuation : AsyncStream < Data > . Continuation !
43- self . messageStream = AsyncStream { continuation = $0 }
44- self . messageContinuation = continuation
45- }
20+ #if canImport(Darwin) || canImport(Glibc) || canImport(Musl)
21+ /// Standard input/output transport implementation
22+ public actor StdioTransport : Transport {
23+ private let input : FileDescriptor
24+ private let output : FileDescriptor
25+ public nonisolated let logger : Logger
26+
27+ private var isConnected = false
28+ private let messageStream : AsyncStream < Data >
29+ private let messageContinuation : AsyncStream < Data > . Continuation
30+
31+ public init (
32+ input: FileDescriptor = FileDescriptor . standardInput,
33+ output: FileDescriptor = FileDescriptor . standardOutput,
34+ logger: Logger ? = nil
35+ ) {
36+ self . input = input
37+ self . output = output
38+ self . logger =
39+ logger
40+ ?? Logger (
41+ label: " mcp.transport.stdio " ,
42+ factory: { _ in SwiftLogNoOpLogHandler ( ) } )
43+
44+ // Create message stream
45+ var continuation : AsyncStream < Data > . Continuation !
46+ self . messageStream = AsyncStream { continuation = $0 }
47+ self . messageContinuation = continuation
48+ }
4649
47- public func connect( ) async throws {
48- guard !isConnected else { return }
50+ public func connect( ) async throws {
51+ guard !isConnected else { return }
4952
50- // Set non-blocking mode
51- try setNonBlocking ( fileDescriptor: input)
52- try setNonBlocking ( fileDescriptor: output)
53+ // Set non-blocking mode
54+ try setNonBlocking ( fileDescriptor: input)
55+ try setNonBlocking ( fileDescriptor: output)
5356
54- isConnected = true
55- logger. info ( " Transport connected successfully " )
57+ isConnected = true
58+ logger. info ( " Transport connected successfully " )
5659
57- // Start reading loop in background
58- Task {
59- await readLoop ( )
60+ // Start reading loop in background
61+ Task {
62+ await readLoop ( )
63+ }
6064 }
61- }
6265
63- private func setNonBlocking( fileDescriptor: FileDescriptor ) throws {
64- #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(Linux)
66+ private func setNonBlocking( fileDescriptor: FileDescriptor ) throws {
6567 // Get current flags
6668 let flags = fcntl ( fileDescriptor. rawValue, F_GETFL)
6769 guard flags >= 0 else {
@@ -73,100 +75,94 @@ public actor StdioTransport: Transport {
7375 guard result >= 0 else {
7476 throw MCPError . transportError ( Errno ( rawValue: CInt ( errno) ) )
7577 }
76- #else
77- // For platforms where non-blocking operations aren't supported
78- throw MCPError . internalError ( " Setting non-blocking mode not supported on this platform " )
79- #endif
80- }
78+ }
8179
82- private func readLoop( ) async {
83- let bufferSize = 4096
84- var buffer = [ UInt8] ( repeating: 0 , count: bufferSize)
85- var pendingData = Data ( )
80+ private func readLoop( ) async {
81+ let bufferSize = 4096
82+ var buffer = [ UInt8] ( repeating: 0 , count: bufferSize)
83+ var pendingData = Data ( )
8684
87- while isConnected && !Task. isCancelled {
88- do {
89- let bytesRead = try buffer. withUnsafeMutableBufferPointer { pointer in
90- try input. read ( into: UnsafeMutableRawBufferPointer ( pointer) )
91- }
85+ while isConnected && !Task. isCancelled {
86+ do {
87+ let bytesRead = try buffer. withUnsafeMutableBufferPointer { pointer in
88+ try input. read ( into: UnsafeMutableRawBufferPointer ( pointer) )
89+ }
9290
93- if bytesRead == 0 {
94- logger. notice ( " EOF received " )
95- break
96- }
91+ if bytesRead == 0 {
92+ logger. notice ( " EOF received " )
93+ break
94+ }
9795
98- pendingData. append ( Data ( buffer [ ..< bytesRead] ) )
96+ pendingData. append ( Data ( buffer [ ..< bytesRead] ) )
9997
100- // Process complete messages
101- while let newlineIndex = pendingData. firstIndex ( of: UInt8 ( ascii: " \n " ) ) {
102- let messageData = pendingData [ ..< newlineIndex]
103- pendingData = pendingData [ ( newlineIndex + 1 ) ... ]
98+ // Process complete messages
99+ while let newlineIndex = pendingData. firstIndex ( of: UInt8 ( ascii: " \n " ) ) {
100+ let messageData = pendingData [ ..< newlineIndex]
101+ pendingData = pendingData [ ( newlineIndex + 1 ) ... ]
104102
105- if !messageData. isEmpty {
106- logger. debug ( " Message received " , metadata: [ " size " : " \( messageData. count) " ] )
107- messageContinuation. yield ( Data ( messageData) )
103+ if !messageData. isEmpty {
104+ logger. debug (
105+ " Message received " , metadata: [ " size " : " \( messageData. count) " ] )
106+ messageContinuation. yield ( Data ( messageData) )
107+ }
108108 }
109+ } catch let error where MCPError . isResourceTemporarilyUnavailable ( error) {
110+ try ? await Task . sleep ( for: . milliseconds( 10 ) )
111+ continue
112+ } catch {
113+ if !Task. isCancelled {
114+ logger. error ( " Read error occurred " , metadata: [ " error " : " \( error) " ] )
115+ }
116+ break
109117 }
110- } catch let error where MCPError . isResourceTemporarilyUnavailable ( error) {
111- try ? await Task . sleep ( for: . milliseconds( 10 ) )
112- continue
113- } catch {
114- if !Task. isCancelled {
115- logger. error ( " Read error occurred " , metadata: [ " error " : " \( error) " ] )
116- }
117- break
118118 }
119- }
120119
121- messageContinuation. finish ( )
122- }
120+ messageContinuation. finish ( )
121+ }
123122
124- public func disconnect( ) async {
125- guard isConnected else { return }
126- isConnected = false
127- messageContinuation. finish ( )
128- logger. info ( " Transport disconnected " )
129- }
123+ public func disconnect( ) async {
124+ guard isConnected else { return }
125+ isConnected = false
126+ messageContinuation. finish ( )
127+ logger. info ( " Transport disconnected " )
128+ }
130129
131- public func send( _ message: Data ) async throws {
132- guard isConnected else {
133- #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(Linux)
130+ public func send( _ message: Data ) async throws {
131+ guard isConnected else {
134132 throw MCPError . transportError ( Errno ( rawValue: ENOTCONN) )
135- #else
136- throw MCPError . internalError ( " Transport not connected " )
137- #endif
138- }
133+ }
139134
140- // Add newline as delimiter
141- var messageWithNewline = message
142- messageWithNewline. append ( UInt8 ( ascii: " \n " ) )
135+ // Add newline as delimiter
136+ var messageWithNewline = message
137+ messageWithNewline. append ( UInt8 ( ascii: " \n " ) )
143138
144- var remaining = messageWithNewline
145- while !remaining. isEmpty {
146- do {
147- let written = try remaining. withUnsafeBytes { buffer in
148- try output. write ( UnsafeRawBufferPointer ( buffer) )
149- }
150- if written > 0 {
151- remaining = remaining. dropFirst ( written)
139+ var remaining = messageWithNewline
140+ while !remaining. isEmpty {
141+ do {
142+ let written = try remaining. withUnsafeBytes { buffer in
143+ try output. write ( UnsafeRawBufferPointer ( buffer) )
144+ }
145+ if written > 0 {
146+ remaining = remaining. dropFirst ( written)
147+ }
148+ } catch let error where MCPError . isResourceTemporarilyUnavailable ( error) {
149+ try await Task . sleep ( for: . milliseconds( 10 ) )
150+ continue
151+ } catch {
152+ throw MCPError . transportError ( error)
152153 }
153- } catch let error where MCPError . isResourceTemporarilyUnavailable ( error) {
154- try await Task . sleep ( for: . milliseconds( 10 ) )
155- continue
156- } catch {
157- throw MCPError . transportError ( error)
158154 }
159155 }
160- }
161156
162- public func receive( ) -> AsyncThrowingStream < Data , Swift . Error > {
163- return AsyncThrowingStream { continuation in
164- Task {
165- for await message in messageStream {
166- continuation. yield ( message)
157+ public func receive( ) -> AsyncThrowingStream < Data , Swift . Error > {
158+ return AsyncThrowingStream { continuation in
159+ Task {
160+ for await message in messageStream {
161+ continuation. yield ( message)
162+ }
163+ continuation. finish ( )
167164 }
168- continuation. finish ( )
169165 }
170166 }
171167 }
172- }
168+ #endif
0 commit comments