@@ -5,9 +5,40 @@ import struct Foundation.Data
5
5
#if canImport(Network)
6
6
import Network
7
7
8
- /// Network connection based transport implementation
8
+ /// An implementation of a custom MCP transport using Apple's Network framework.
9
+ ///
10
+ /// This transport allows MCP clients and servers to communicate over TCP/UDP connections
11
+ /// using Apple's Network framework.
12
+ ///
13
+ /// - Important: This transport is available exclusively on Apple platforms
14
+ /// (macOS, iOS, watchOS, tvOS, visionOS) as it depends on the Network framework.
15
+ ///
16
+ /// ## Example Usage
17
+ ///
18
+ /// ```swift
19
+ /// import MCP
20
+ /// import Network
21
+ ///
22
+ /// // Create a TCP connection to a server
23
+ /// let connection = NWConnection(
24
+ /// host: NWEndpoint.Host("localhost"),
25
+ /// port: NWEndpoint.Port(8080)!,
26
+ /// using: .tcp
27
+ /// )
28
+ ///
29
+ /// // Initialize the transport with the connection
30
+ /// let transport = NetworkTransport(connection: connection)
31
+ ///
32
+ /// // Use the transport with an MCP client
33
+ /// let client = Client(name: "MyApp", version: "1.0.0")
34
+ /// try await client.connect(transport: transport)
35
+ ///
36
+ /// // Initialize the connection
37
+ /// let result = try await client.initialize()
38
+ /// ```
9
39
public actor NetworkTransport : Transport {
10
40
private let connection : NWConnection
41
+ /// Logger instance for transport-related events
11
42
public nonisolated let logger : Logger
12
43
13
44
private var isConnected = false
@@ -17,6 +48,11 @@ import struct Foundation.Data
17
48
// Track connection state for continuations
18
49
private var connectionContinuationResumed = false
19
50
51
+ /// Creates a new NetworkTransport with the specified NWConnection
52
+ ///
53
+ /// - Parameters:
54
+ /// - connection: The NWConnection to use for communication
55
+ /// - logger: Optional logger instance for transport events
20
56
public init ( connection: NWConnection , logger: Logger ? = nil ) {
21
57
self . connection = connection
22
58
self . logger =
@@ -32,7 +68,12 @@ import struct Foundation.Data
32
68
self . messageContinuation = continuation
33
69
}
34
70
35
- /// Connects to the network transport
71
+ /// Establishes connection with the transport
72
+ ///
73
+ /// This initiates the NWConnection and waits for it to become ready.
74
+ /// Once the connection is established, it starts the message receiving loop.
75
+ ///
76
+ /// - Throws: Error if the connection fails to establish
36
77
public func connect( ) async throws {
37
78
guard !isConnected else { return }
38
79
@@ -77,6 +118,9 @@ import struct Foundation.Data
77
118
}
78
119
}
79
120
121
+ /// Handles when the connection reaches the ready state
122
+ ///
123
+ /// - Parameter continuation: The continuation to resume when connection is ready
80
124
private func handleConnectionReady( continuation: CheckedContinuation < Void , Swift . Error > )
81
125
async
82
126
{
@@ -90,6 +134,11 @@ import struct Foundation.Data
90
134
}
91
135
}
92
136
137
+ /// Handles connection failure
138
+ ///
139
+ /// - Parameters:
140
+ /// - error: The error that caused the connection to fail
141
+ /// - continuation: The continuation to resume with the error
93
142
private func handleConnectionFailed(
94
143
error: Swift . Error , continuation: CheckedContinuation < Void , Swift . Error >
95
144
) async {
@@ -100,6 +149,9 @@ import struct Foundation.Data
100
149
}
101
150
}
102
151
152
+ /// Handles connection cancellation
153
+ ///
154
+ /// - Parameter continuation: The continuation to resume with cancellation error
103
155
private func handleConnectionCancelled( continuation: CheckedContinuation < Void , Swift . Error > )
104
156
async
105
157
{
@@ -110,6 +162,10 @@ import struct Foundation.Data
110
162
}
111
163
}
112
164
165
+ /// Disconnects from the transport
166
+ ///
167
+ /// This cancels the NWConnection, finalizes the message stream,
168
+ /// and releases associated resources.
113
169
public func disconnect( ) async {
114
170
guard isConnected else { return }
115
171
isConnected = false
@@ -118,6 +174,13 @@ import struct Foundation.Data
118
174
logger. info ( " Network transport disconnected " )
119
175
}
120
176
177
+ /// Sends data through the network connection
178
+ ///
179
+ /// This sends a JSON-RPC message through the NWConnection, adding a newline
180
+ /// delimiter to mark the end of the message.
181
+ ///
182
+ /// - Parameter message: The JSON-RPC message to send
183
+ /// - Throws: MCPError for transport failures or connection issues
121
184
public func send( _ message: Data ) async throws {
122
185
guard isConnected else {
123
186
throw MCPError . internalError ( " Transport not connected " )
@@ -158,10 +221,21 @@ import struct Foundation.Data
158
221
}
159
222
}
160
223
224
+ /// Receives data in an async sequence
225
+ ///
226
+ /// This returns an AsyncThrowingStream that emits Data objects representing
227
+ /// each JSON-RPC message received from the network connection.
228
+ ///
229
+ /// - Returns: An AsyncThrowingStream of Data objects
161
230
public func receive( ) -> AsyncThrowingStream < Data , Swift . Error > {
162
231
return messageStream
163
232
}
164
233
234
+ /// Continuous loop to receive and process incoming messages
235
+ ///
236
+ /// This method runs continuously while the connection is active,
237
+ /// receiving data and yielding complete messages to the message stream.
238
+ /// Messages are delimited by newline characters.
165
239
private func receiveLoop( ) async {
166
240
var buffer = Data ( )
167
241
@@ -204,6 +278,10 @@ import struct Foundation.Data
204
278
messageContinuation. finish ( )
205
279
}
206
280
281
+ /// Receives a chunk of data from the network connection
282
+ ///
283
+ /// - Returns: The received data chunk
284
+ /// - Throws: Network errors or transport failures
207
285
private func receiveData( ) async throws -> Data {
208
286
var receiveContinuationResumed = false
209
287
0 commit comments