Add client completion notification and details (#1368)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
4af2596019
commit
b965a7eca6
1 changed files with 691 additions and 31 deletions
|
|
@ -153,6 +153,15 @@ internal sealed partial class McpSessionHandler : IAsyncDisposable
|
|||
/// </summary>
|
||||
public string? NegotiatedProtocolVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a task that completes when the client session has completed, providing details about the closure.
|
||||
/// Completion details are resolved from the transport's channel completion exception: if a transport
|
||||
/// completes its channel with a <see cref="TransportClosedException"/>, the wrapped
|
||||
/// <see cref="ClientCompletionDetails"/> is unwrapped. Otherwise, a default instance is returned.
|
||||
/// </summary>
|
||||
internal Task<ClientCompletionDetails> CompletionTask =>
|
||||
field ??= GetCompletionDetailsAsync(_transport.MessageReader.Completion);
|
||||
|
||||
/// <summary>
|
||||
/// Starts processing messages from the transport. This method will block until the transport is disconnected.
|
||||
/// This is generally started in a background task or thread from the initialization logic of the derived class.
|
||||
|
|
@ -305,6 +314,28 @@ internal sealed partial class McpSessionHandler : IAsyncDisposable
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves <see cref="ClientCompletionDetails"/> from the transport's channel completion.
|
||||
/// If the channel was completed with a <see cref="TransportClosedException"/>, the wrapped
|
||||
/// details are returned. Otherwise a default instance is created from the completion state.
|
||||
/// </summary>
|
||||
private static async Task<ClientCompletionDetails> GetCompletionDetailsAsync(Task channelCompletion)
|
||||
{
|
||||
try
|
||||
{
|
||||
await channelCompletion.ConfigureAwait(false);
|
||||
return new ClientCompletionDetails();
|
||||
}
|
||||
catch (TransportClosedException tce)
|
||||
{
|
||||
return tce.Details;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ClientCompletionDetails { Exception = ex };
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleMessageAsync(JsonRpcMessage message, CancellationToken cancellationToken)
|
||||
{
|
||||
Histogram<double> durationMetric = _isServer ? s_serverOperationDuration : s_clientOperationDuration;
|
||||
|
|
@ -885,9 +916,11 @@ internal sealed partial class McpSessionHandler : IAsyncDisposable
|
|||
{
|
||||
await _messageProcessingTask.ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
catch
|
||||
{
|
||||
// Ignore cancellation
|
||||
// Ignore exceptions from the message processing loop. It may fault with
|
||||
// OperationCanceledException on normal shutdown or TransportClosedException
|
||||
// when the transport's channel completes with an error.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue