11using Microsoft . Extensions . Logging ;
22using Microsoft . Extensions . Logging . Abstractions ;
3- using ModelContextProtocol . Protocol . Auth ;
43using ModelContextProtocol . Protocol . Messages ;
54using ModelContextProtocol . Utils ;
65using ModelContextProtocol . Utils . Json ;
76using System . Diagnostics ;
8- using System . Net ;
97using System . Net . Http . Headers ;
108using System . Net . ServerSentEvents ;
119using System . Text ;
@@ -26,7 +24,6 @@ internal sealed partial class SseClientSessionTransport : TransportBase
2624 private Task ? _receiveTask ;
2725 private readonly ILogger _logger ;
2826 private readonly TaskCompletionSource < bool > _connectionEstablished ;
29- private readonly IAuthorizationHandler _authorizationHandler ;
3027
3128 /// <summary>
3229 /// SSE transport for client endpoints. Unlike stdio it does not launch a process, but connects to an existing server.
@@ -48,18 +45,6 @@ public SseClientSessionTransport(SseClientTransportOptions transportOptions, Htt
4845 _connectionCts = new CancellationTokenSource ( ) ;
4946 _logger = ( ILogger ? ) loggerFactory ? . CreateLogger < SseClientTransport > ( ) ?? NullLogger . Instance ;
5047 _connectionEstablished = new TaskCompletionSource < bool > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
51-
52- // Initialize the authorization handler
53- if ( transportOptions . AuthorizationOptions ? . AuthorizationHandler != null )
54- {
55- // Use explicitly provided handler
56- _authorizationHandler = transportOptions . AuthorizationOptions . AuthorizationHandler ;
57- }
58- else
59- {
60- // Create default handler with auth options
61- _authorizationHandler = new DefaultAuthorizationHandler ( loggerFactory , transportOptions . AuthorizationOptions ) ;
62- }
6348 }
6449
6550 /// <inheritdoc/>
@@ -89,48 +74,18 @@ public override async Task SendMessageAsync(
8974 if ( _messageEndpoint == null )
9075 throw new InvalidOperationException ( "Transport not connected" ) ;
9176
77+ using var content = new StringContent (
78+ JsonSerializer . Serialize ( message , McpJsonUtilities . JsonContext . Default . JsonRpcMessage ) ,
79+ Encoding . UTF8 ,
80+ "application/json"
81+ ) ;
82+
9283 string messageId = "(no id)" ;
9384
9485 if ( message is JsonRpcMessageWithId messageWithId )
9586 {
9687 messageId = messageWithId . Id . ToString ( ) ;
9788 }
98-
99- // Send the request, handling potential auth challenges
100- HttpResponseMessage ? response = null ;
101- bool authRetry = false ;
102-
103- do
104- {
105- authRetry = false ;
106-
107- // Create a new request for each attempt
108- using var currentRequest = new HttpRequestMessage ( HttpMethod . Post , _messageEndpoint ) ;
109- currentRequest . Content = new StringContent (
110- JsonSerializer . Serialize ( message , McpJsonUtilities . JsonContext . Default . JsonRpcMessage ) ,
111- Encoding . UTF8 ,
112- "application/json"
113- ) ;
114-
115- // Add authorization headers if needed - the handler will only add headers if auth is required
116- await _authorizationHandler . AuthenticateRequestAsync ( currentRequest ) . ConfigureAwait ( false ) ;
117-
118- // Copy additional headers
119- CopyAdditionalHeaders ( currentRequest . Headers ) ;
120-
121- // Dispose previous response before making a new request
122- response ? . Dispose ( ) ;
123-
124- response = await _httpClient . SendAsync ( currentRequest , cancellationToken ) . ConfigureAwait ( false ) ;
125-
126- // Handle 401 Unauthorized response - this will only execute if the server requires auth
127- if ( response . StatusCode == HttpStatusCode . Unauthorized )
128- {
129- // Try to handle the unauthorized response
130- authRetry = await _authorizationHandler . HandleUnauthorizedResponseAsync (
131- response , _messageEndpoint ) . ConfigureAwait ( false ) ;
132- }
133- } while ( authRetry ) ;
13489
13590 using var httpRequestMessage = new HttpRequestMessage ( HttpMethod . Post , _messageEndpoint )
13691 {
@@ -139,25 +94,26 @@ public override async Task SendMessageAsync(
13994 StreamableHttpClientSessionTransport . CopyAdditionalHeaders ( httpRequestMessage . Headers , _options . AdditionalHeaders ) ;
14095 var response = await _httpClient . SendAsync ( httpRequestMessage , cancellationToken ) . ConfigureAwait ( false ) ;
14196
142- var responseContent = await response . Content . ReadAsStringAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
97+ response . EnsureSuccessStatusCode ( ) ;
14398
144- // Check if the message was an initialize request
145- if ( message is JsonRpcRequest request && request . Method == RequestMethods . Initialize )
146- {
147- // If the response is not a JSON-RPC response, it is an SSE message
148- if ( string . IsNullOrEmpty ( responseContent ) || responseContent . Equals ( "accepted" , StringComparison . OrdinalIgnoreCase ) )
149- {
150- LogAcceptedPost ( Name , messageId ) ;
151- // The response will arrive as an SSE message
152- }
153- else
154- {
155- JsonRpcResponse initializeResponse = JsonSerializer . Deserialize ( responseContent , McpJsonUtilities . JsonContext . Default . JsonRpcResponse ) ??
156- throw new InvalidOperationException ( "Failed to initialize client" ) ;
99+ var responseContent = await response . Content . ReadAsStringAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
157100
158101 if ( string . IsNullOrEmpty ( responseContent ) || responseContent . Equals ( "accepted" , StringComparison . OrdinalIgnoreCase ) )
159102 {
160- response . Dispose ( ) ;
103+ LogAcceptedPost ( Name , messageId ) ;
104+ }
105+ else
106+ {
107+ if ( _logger . IsEnabled ( LogLevel . Trace ) )
108+ {
109+ LogRejectedPostSensitive ( Name , messageId , responseContent ) ;
110+ }
111+ else
112+ {
113+ LogRejectedPost ( Name , messageId ) ;
114+ }
115+
116+ throw new InvalidOperationException ( "Failed to send message" ) ;
161117 }
162118 }
163119
0 commit comments