Skip to content

Commit daef492

Browse files
authored
Improve documentation comments for transport types (#98)
* Add example usage to HTTPClientTransport documentation comments * Add documentation comments to NetworkTransport * Improve documentation comments for StdioTransport
1 parent bdaa258 commit daef492

File tree

3 files changed

+159
-7
lines changed

3 files changed

+159
-7
lines changed

Sources/MCP/Base/Transports/HTTPClientTransport.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,27 @@ import Logging
2626
/// - Streaming HTTP with SSE (`streaming=true`): Enables server-to-client push messages
2727
///
2828
/// - Important: Server-Sent Events (SSE) functionality is not supported on Linux platforms.
29+
///
30+
/// ## Example Usage
31+
///
32+
/// ```swift
33+
/// import MCP
34+
///
35+
/// // Create a streaming HTTP transport
36+
/// let transport = HTTPClientTransport(
37+
/// endpoint: URL(string: "http://localhost:8080")!,
38+
/// )
39+
///
40+
/// // Initialize the client with streaming transport
41+
/// let client = Client(name: "MyApp", version: "1.0.0")
42+
/// try await client.connect(transport: transport)
43+
///
44+
/// // Initialize the connection
45+
/// let result = try await client.initialize()
46+
///
47+
/// // The transport will automatically handle SSE events
48+
/// // and deliver them through the client's notification handlers
49+
/// ```
2950
public actor HTTPClientTransport: Transport {
3051
/// The server endpoint URL to connect to
3152
public let endpoint: URL

Sources/MCP/Base/Transports/NetworkTransport.swift

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,40 @@ import struct Foundation.Data
55
#if canImport(Network)
66
import Network
77

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+
/// ```
939
public actor NetworkTransport: Transport {
1040
private let connection: NWConnection
41+
/// Logger instance for transport-related events
1142
public nonisolated let logger: Logger
1243

1344
private var isConnected = false
@@ -17,6 +48,11 @@ import struct Foundation.Data
1748
// Track connection state for continuations
1849
private var connectionContinuationResumed = false
1950

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
2056
public init(connection: NWConnection, logger: Logger? = nil) {
2157
self.connection = connection
2258
self.logger =
@@ -32,7 +68,12 @@ import struct Foundation.Data
3268
self.messageContinuation = continuation
3369
}
3470

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
3677
public func connect() async throws {
3778
guard !isConnected else { return }
3879

@@ -77,6 +118,9 @@ import struct Foundation.Data
77118
}
78119
}
79120

121+
/// Handles when the connection reaches the ready state
122+
///
123+
/// - Parameter continuation: The continuation to resume when connection is ready
80124
private func handleConnectionReady(continuation: CheckedContinuation<Void, Swift.Error>)
81125
async
82126
{
@@ -90,6 +134,11 @@ import struct Foundation.Data
90134
}
91135
}
92136

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
93142
private func handleConnectionFailed(
94143
error: Swift.Error, continuation: CheckedContinuation<Void, Swift.Error>
95144
) async {
@@ -100,6 +149,9 @@ import struct Foundation.Data
100149
}
101150
}
102151

152+
/// Handles connection cancellation
153+
///
154+
/// - Parameter continuation: The continuation to resume with cancellation error
103155
private func handleConnectionCancelled(continuation: CheckedContinuation<Void, Swift.Error>)
104156
async
105157
{
@@ -110,6 +162,10 @@ import struct Foundation.Data
110162
}
111163
}
112164

165+
/// Disconnects from the transport
166+
///
167+
/// This cancels the NWConnection, finalizes the message stream,
168+
/// and releases associated resources.
113169
public func disconnect() async {
114170
guard isConnected else { return }
115171
isConnected = false
@@ -118,6 +174,13 @@ import struct Foundation.Data
118174
logger.info("Network transport disconnected")
119175
}
120176

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
121184
public func send(_ message: Data) async throws {
122185
guard isConnected else {
123186
throw MCPError.internalError("Transport not connected")
@@ -158,10 +221,21 @@ import struct Foundation.Data
158221
}
159222
}
160223

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
161230
public func receive() -> AsyncThrowingStream<Data, Swift.Error> {
162231
return messageStream
163232
}
164233

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.
165239
private func receiveLoop() async {
166240
var buffer = Data()
167241

@@ -204,6 +278,10 @@ import struct Foundation.Data
204278
messageContinuation.finish()
205279
}
206280

281+
/// Receives a chunk of data from the network connection
282+
///
283+
/// - Returns: The received data chunk
284+
/// - Throws: Network errors or transport failures
207285
private func receiveData() async throws -> Data {
208286
var receiveContinuationResumed = false
209287

Sources/MCP/Base/Transports/StdioTransport.swift

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,54 @@ import struct Foundation.Data
1616
#endif
1717

1818
#if canImport(Darwin) || canImport(Glibc)
19-
/// Standard input/output transport implementation
19+
/// An implementation of the MCP stdio transport protocol.
2020
///
21-
/// This transport supports JSON-RPC 2.0 messages, including individual requests,
22-
/// notifications, responses, and batches containing multiple requests/notifications.
21+
/// This transport implements the [stdio transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#stdio)
22+
/// specification from the Model Context Protocol.
2323
///
24-
/// Messages are delimited by newlines and must not contain embedded newlines.
25-
/// Each message must be a complete, valid JSON object or array (for batches).
24+
/// The stdio transport works by:
25+
/// - Reading JSON-RPC messages from standard input
26+
/// - Writing JSON-RPC messages to standard output
27+
/// - Using newline characters as message delimiters
28+
/// - Supporting non-blocking I/O operations
29+
///
30+
/// This transport is the recommended option for most MCP applications due to its
31+
/// simplicity and broad platform support.
32+
///
33+
/// - Important: This transport is available on Apple platforms and Linux distributions with glibc
34+
/// (Ubuntu, Debian, Fedora, CentOS, RHEL).
35+
///
36+
/// ## Example Usage
37+
///
38+
/// ```swift
39+
/// import MCP
40+
///
41+
/// // Initialize the client
42+
/// let client = Client(name: "MyApp", version: "1.0.0")
43+
///
44+
/// // Create a transport and connect
45+
/// let transport = StdioTransport()
46+
/// try await client.connect(transport: transport)
47+
///
48+
/// // Initialize the connection
49+
/// let result = try await client.initialize()
50+
/// ```
2651
public actor StdioTransport: Transport {
2752
private let input: FileDescriptor
2853
private let output: FileDescriptor
54+
/// Logger instance for transport-related events
2955
public nonisolated let logger: Logger
3056

3157
private var isConnected = false
3258
private let messageStream: AsyncThrowingStream<Data, Swift.Error>
3359
private let messageContinuation: AsyncThrowingStream<Data, Swift.Error>.Continuation
3460

61+
/// Creates a new stdio transport with the specified file descriptors
62+
///
63+
/// - Parameters:
64+
/// - input: File descriptor for reading (defaults to standard input)
65+
/// - output: File descriptor for writing (defaults to standard output)
66+
/// - logger: Optional logger instance for transport events
3567
public init(
3668
input: FileDescriptor = FileDescriptor.standardInput,
3769
output: FileDescriptor = FileDescriptor.standardOutput,
@@ -51,6 +83,12 @@ import struct Foundation.Data
5183
self.messageContinuation = continuation
5284
}
5385

86+
/// Establishes connection with the transport
87+
///
88+
/// This method configures the file descriptors for non-blocking I/O
89+
/// and starts the background message reading loop.
90+
///
91+
/// - Throws: Error if the file descriptors cannot be configured
5492
public func connect() async throws {
5593
guard !isConnected else { return }
5694

@@ -67,6 +105,10 @@ import struct Foundation.Data
67105
}
68106
}
69107

108+
/// Configures a file descriptor for non-blocking I/O
109+
///
110+
/// - Parameter fileDescriptor: The file descriptor to configure
111+
/// - Throws: Error if the operation fails
70112
private func setNonBlocking(fileDescriptor: FileDescriptor) throws {
71113
#if canImport(Darwin) || canImport(Glibc)
72114
// Get current flags
@@ -87,6 +129,11 @@ import struct Foundation.Data
87129
#endif
88130
}
89131

132+
/// Continuous loop that reads and processes incoming messages
133+
///
134+
/// This method runs in the background while the transport is connected,
135+
/// parsing complete messages delimited by newlines and yielding them
136+
/// to the message stream.
90137
private func readLoop() async {
91138
let bufferSize = 4096
92139
var buffer = [UInt8](repeating: 0, count: bufferSize)
@@ -130,6 +177,9 @@ import struct Foundation.Data
130177
messageContinuation.finish()
131178
}
132179

180+
/// Disconnects from the transport
181+
///
182+
/// This stops the message reading loop and releases associated resources.
133183
public func disconnect() async {
134184
guard isConnected else { return }
135185
isConnected = false
@@ -144,6 +194,7 @@ import struct Foundation.Data
144194
/// according to the JSON-RPC 2.0 specification.
145195
///
146196
/// - Parameter message: The message data to send (without a trailing newline)
197+
/// - Throws: Error if the message cannot be sent
147198
public func send(_ message: Data) async throws {
148199
guard isConnected else {
149200
throw MCPError.transportError(Errno(rawValue: ENOTCONN))
@@ -176,6 +227,8 @@ import struct Foundation.Data
176227
/// Messages may be individual JSON-RPC requests, notifications, responses,
177228
/// or batches containing multiple requests/notifications encoded as JSON arrays.
178229
/// Each message is guaranteed to be a complete JSON object or array.
230+
///
231+
/// - Returns: An AsyncThrowingStream of Data objects representing JSON-RPC messages
179232
public func receive() -> AsyncThrowingStream<Data, Swift.Error> {
180233
return messageStream
181234
}

0 commit comments

Comments
 (0)