1- using  System . Diagnostics ; 
2- using  System . Text . Json ; 
1+ using  Microsoft . Extensions . Logging ; 
2+ using  Microsoft . Extensions . Logging . Abstractions ; 
33using  ModelContextProtocol . Configuration ; 
44using  ModelContextProtocol . Logging ; 
55using  ModelContextProtocol . Protocol . Messages ; 
66using  ModelContextProtocol . Utils ; 
77using  ModelContextProtocol . Utils . Json ; 
8- using  Microsoft . Extensions . Logging ; 
9- using  Microsoft . Extensions . Logging . Abstractions ; 
8+ using  System . Diagnostics ; 
9+ using  System . Text ; 
10+ using  System . Text . Json ; 
1011
1112namespace  ModelContextProtocol . Protocol . Transport ; 
1213
@@ -20,6 +21,8 @@ public sealed class StdioClientTransport : TransportBase, IClientTransport
2021    private  readonly  ILogger  _logger ; 
2122    private  readonly  JsonSerializerOptions  _jsonOptions ; 
2223    private  Process ?  _process ; 
24+     private  StreamWriter ?  _stdInWriter ; 
25+     private  StreamReader ?  _stdOutReader ; 
2326    private  Task ?  _readTask ; 
2427    private  CancellationTokenSource ?  _shutdownCts ; 
2528    private  bool  _processStarted ; 
@@ -99,6 +102,13 @@ public async Task ConnectAsync(CancellationToken cancellationToken = default)
99102            } 
100103            _logger . TransportProcessStarted ( EndpointName ,  _process . Id ) ; 
101104            _processStarted  =  true ; 
105+             
106+             // Create streams with explicit UTF-8 encoding to ensure proper Unicode character handling 
107+             // This is especially important for non-ASCII characters like Chinese text and emoji 
108+             var  utf8Encoding  =  new  UTF8Encoding ( false ) ;  // No BOM 
109+             _stdInWriter  =  new  StreamWriter ( _process . StandardInput . BaseStream ,  utf8Encoding )  {  AutoFlush  =  true  } ; 
110+             _stdOutReader  =  new  StreamReader ( _process . StandardOutput . BaseStream ,  utf8Encoding ) ; 
111+             
102112            _process . BeginErrorReadLine ( ) ; 
103113
104114            // Start reading messages in the background 
@@ -118,7 +128,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken = default)
118128    /// <inheritdoc/> 
119129    public  override  async  Task  SendMessageAsync ( IJsonRpcMessage  message ,  CancellationToken  cancellationToken  =  default ) 
120130    { 
121-         if  ( ! IsConnected  ||  _process ? . HasExited  ==  true ) 
131+         if  ( ! IsConnected  ||  _process ? . HasExited  ==  true   ||   _stdInWriter   ==   null ) 
122132        { 
123133            _logger . TransportNotConnected ( EndpointName ) ; 
124134            throw  new  McpTransportException ( "Transport is not connected" ) ; 
@@ -134,10 +144,11 @@ public override async Task SendMessageAsync(IJsonRpcMessage message, Cancellatio
134144        { 
135145            var  json  =  JsonSerializer . Serialize ( message ,  _jsonOptions . GetTypeInfo < IJsonRpcMessage > ( ) ) ; 
136146            _logger . TransportSendingMessage ( EndpointName ,  id ,  json ) ; 
147+             _logger . TransportMessageBytesUtf8 ( EndpointName ,  json ) ; 
137148
138-             // Write the message followed by a newline 
139-             await  _process ! . StandardInput . WriteLineAsync ( json . AsMemory ( ) ,   cancellationToken ) . ConfigureAwait ( false ) ; 
140-             await  _process . StandardInput . FlushAsync ( cancellationToken ) . ConfigureAwait ( false ) ; 
149+             // Write the message followed by a newline using our UTF-8 writer  
150+             await  _stdInWriter . WriteLineAsync ( json ) . ConfigureAwait ( false ) ; 
151+             await  _stdInWriter . FlushAsync ( cancellationToken ) . ConfigureAwait ( false ) ; 
141152
142153            _logger . TransportSentMessage ( EndpointName ,  id ) ; 
143154        } 
@@ -161,12 +172,10 @@ private async Task ReadMessagesAsync(CancellationToken cancellationToken)
161172        { 
162173            _logger . TransportEnteringReadMessagesLoop ( EndpointName ) ; 
163174
164-             using  var  reader  =  _process ! . StandardOutput ; 
165- 
166-             while  ( ! cancellationToken . IsCancellationRequested  &&  ! _process . HasExited ) 
175+             while  ( ! cancellationToken . IsCancellationRequested  &&  ! _process ! . HasExited  &&  _stdOutReader  !=  null ) 
167176            { 
168177                _logger . TransportWaitingForMessage ( EndpointName ) ; 
169-                 var  line  =  await  reader . ReadLineAsync ( cancellationToken ) . ConfigureAwait ( false ) ; 
178+                 var  line  =  await  _stdOutReader . ReadLineAsync ( cancellationToken ) . ConfigureAwait ( false ) ; 
170179                if  ( line  ==  null ) 
171180                { 
172181                    _logger . TransportEndOfStream ( EndpointName ) ; 
@@ -179,6 +188,7 @@ private async Task ReadMessagesAsync(CancellationToken cancellationToken)
179188                } 
180189
181190                _logger . TransportReceivedMessage ( EndpointName ,  line ) ; 
191+                 _logger . TransportMessageBytesUtf8 ( EndpointName ,  line ) ; 
182192
183193                await  ProcessMessageAsync ( line ,  cancellationToken ) . ConfigureAwait ( false ) ; 
184194            } 
@@ -230,14 +240,28 @@ private async Task ProcessMessageAsync(string line, CancellationToken cancellati
230240    private  async  Task  CleanupAsync ( CancellationToken  cancellationToken ) 
231241    { 
232242        _logger . TransportCleaningUp ( EndpointName ) ; 
233-         if  ( _process  !=  null  &&  _processStarted  &&  ! _process . HasExited ) 
243+         
244+         if  ( _stdInWriter  !=  null ) 
234245        { 
235246            try 
236247            { 
237-                 // Try to close stdin to signal the process to exit 
238248                _logger . TransportClosingStdin ( EndpointName ) ; 
239-                 _process . StandardInput . Close ( ) ; 
249+                 _stdInWriter . Close ( ) ; 
250+             } 
251+             catch  ( Exception  ex ) 
252+             { 
253+                 _logger . TransportShutdownFailed ( EndpointName ,  ex ) ; 
254+             } 
240255
256+             _stdInWriter  =  null ; 
257+         } 
258+         
259+         _stdOutReader  =  null ; 
260+         
261+         if  ( _process  !=  null  &&  _processStarted  &&  ! _process . HasExited ) 
262+         { 
263+             try 
264+             { 
241265                // Wait for the process to exit 
242266                _logger . TransportWaitingForShutdown ( EndpointName ) ; 
243267
0 commit comments