Skip to content
This repository was archived by the owner on May 29, 2025. It is now read-only.

Commit 001947d

Browse files
jamesrochabrunGui Sabrangsabran
authored
Adding Chat demo (Not stream) (#11)
* Chat demo * Typo * Comments * Adding openAi dependency * Getting ready for openai changes * OpenAI tools * Adding final tools conversion for openai * Adding openai demo * Adding hint code * lint, mostly * fix json data being spread over several chunks received from stdio * update readme for sandbox * updating branch with stream changes * Solving problem for env * Update MCPClient/Sources/stdioTransport/DataChannel+StdioProcess.swift Co-authored-by: Guillaume Sabran <[email protected]> * Update MCPClient/Sources/stdioTransport/DataChannel+StdioProcess.swift Co-authored-by: Guillaume Sabran <[email protected]> * pr feedback * Update MCPInterface/Sources/helpers/JSON+Streaming.swift Co-authored-by: Guillaume Sabran <[email protected]> * lint * Avoding print rules * lint * More linting --------- Co-authored-by: Gui Sabran <gsabran@www.com> Co-authored-by: Guillaume Sabran <[email protected]>
1 parent 7864ffc commit 001947d

File tree

31 files changed

+2967
-13
lines changed

31 files changed

+2967
-13
lines changed

MCPClient/Sources/DataChannel+StdioProcess.swift renamed to MCPClient/Sources/stdioTransport/DataChannel+StdioProcess.swift

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
import Foundation
33
import JSONRPC
4+
import MCPInterface
45
import OSLog
56

67
private let logger = Logger(
@@ -42,17 +43,18 @@ extension JSONRPCSetupError: LocalizedError {
4243
}
4344
}
4445

45-
extension DataChannel {
46+
extension Transport {
4647

4748
// MARK: Public
4849

50+
/// Creates a new `Transport` by launching the given executable with the specified arguments and attaching to its standard IO.
4951
public static func stdioProcess(
5052
_ executable: String,
5153
args: [String] = [],
5254
cwd: String? = nil,
5355
env: [String: String]? = nil,
5456
verbose: Bool = false)
55-
throws -> DataChannel
57+
throws -> Transport
5658
{
5759
if verbose {
5860
let command = "\(executable) \(args.joined(separator: " "))"
@@ -103,10 +105,11 @@ extension DataChannel {
103105
return try stdioProcess(unlaunchedProcess: process, verbose: verbose)
104106
}
105107

108+
/// Creates a new `Transport` by launching the given process and attaching to its standard IO.
106109
public static func stdioProcess(
107110
unlaunchedProcess process: Process,
108111
verbose: Bool = false)
109-
throws -> DataChannel
112+
throws -> Transport
110113
{
111114
guard
112115
let stdin = process.standardInput as? Pipe,
@@ -119,7 +122,6 @@ extension DataChannel {
119122
// Run the process
120123
var stdoutData = Data()
121124
var stderrData = Data()
122-
123125
let outStream: AsyncStream<Data>
124126
if verbose {
125127
// As we are both reading stdout here in this function, and want to make the stream readable to the caller,
@@ -131,7 +133,7 @@ extension DataChannel {
131133
}
132134

133135
Task {
134-
for await data in stdout.fileHandleForReading.dataStream {
136+
for await data in stdout.fileHandleForReading.dataStream.jsonStream {
135137
stdoutData.append(data)
136138
outContinuation?.yield(data)
137139

@@ -150,10 +152,10 @@ extension DataChannel {
150152
}
151153
} else {
152154
// If we are not in verbose mode, we are not reading from stdout internally, so we can just return the stream directly.
153-
outStream = stdout.fileHandleForReading.dataStream
155+
outStream = stdout.fileHandleForReading.dataStream.jsonStream
154156
}
155157

156-
// Ensures that the process is terminated when the DataChannel is de-referenced.
158+
// Ensures that the process is terminated when the Transport is de-referenced.
157159
let lifetime = Lifetime {
158160
if process.isRunning {
159161
process.terminate()
@@ -177,7 +179,7 @@ extension DataChannel {
177179
throw error
178180
}
179181

180-
let writeHandler: DataChannel.WriteHandler = { [lifetime] data in
182+
let writeHandler: Transport.WriteHandler = { [lifetime] data in
181183
_ = lifetime
182184
if verbose {
183185
logger.log("Sending data:\n\(String(data: data, encoding: .utf8) ?? "nil")")
@@ -188,7 +190,7 @@ extension DataChannel {
188190
stdin.fileHandleForWriting.write(Data("\n".utf8))
189191
}
190192

191-
return DataChannel(writeHandler: writeHandler, dataSequence: outStream)
193+
return Transport(writeHandler: writeHandler, dataSequence: outStream)
192194
}
193195

194196
// MARK: Private
@@ -213,10 +215,12 @@ extension DataChannel {
213215
private static func loadZshEnvironment() throws -> [String: String] {
214216
let process = Process()
215217
process.launchPath = "/bin/zsh"
216-
process.arguments = ["-c", "source ~/.zshrc && printenv"]
218+
// Those are loaded for interactive login shell by zsh:
219+
// https://www.freecodecamp.org/news/how-do-zsh-configuration-files-work/
220+
process.arguments = ["-c", "source ~/.zshenv; source ~/.zprofile; source ~/.zshrc; source ~/.zshrc; printenv"]
217221
let env = try getProcessStdout(process: process)
218222

219-
if let path = env?.split(separator: "\n").filter({ $0.starts(with: "PATH=") }).first {
223+
if let path = env?.split(separator: "\n").filter({ $0.starts(with: "PATH=") }).last {
220224
return ["PATH": String(path.dropFirst("PATH=".count))]
221225
} else {
222226
return ProcessInfo.processInfo.environment

0 commit comments

Comments
 (0)