Flow ExecutionContext with JsonRpcMessage (#616)

The primary goal of this change is to support IHttpContextAccessor in tool calls when the Streamable HTTP is in its default non-Stateless mode.
This commit is contained in:
Stephen Halter 2025-07-15 13:58:43 -07:00 • committed by GitHub
commit a88ef0deb7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 61 additions and 14 deletions

View file

@ -91,6 +91,11 @@ internal sealed class StreamableHttpPostTransport(StreamableHttpServerTransport
message.RelatedTransport = this;
if (parentTransport.FlowExecutionContextFromRequests)
{
message.ExecutionContext = ExecutionContext.Capture();
}
await parentTransport.MessageWriter.WriteAsync(message, cancellationToken).ConfigureAwait(false);
}
}

View file

@ -10,7 +10,7 @@ namespace ModelContextProtocol.Server;
/// <remarks>
/// <para>
/// This transport provides one-way communication from server to client using the SSE protocol over HTTP,
/// while receiving client messages through a separate mechanism. It writes messages as
/// while receiving client messages through a separate mechanism. It writes messages as
/// SSE events to a response stream, typically associated with an HTTP response.
/// </para>
/// <para>
@ -36,6 +36,9 @@ public sealed class StreamableHttpServerTransport : ITransport
private int _getRequestStarted;
/// <inheritdoc/>
public string? SessionId { get; set; }
/// <summary>
/// Configures whether the transport should be in stateless mode that does not require all requests for a given session
/// to arrive to the same ASP.NET Core application process. Unsolicited server-to-client messages are not supported in this mode,
@ -45,6 +48,15 @@ public sealed class StreamableHttpServerTransport : ITransport
/// </summary>
public bool Stateless { get; init; }
/// <summary>
/// Gets a value indicating whether the execution context should flow from the calls to <see cref="HandlePostRequest(IDuplexPipe, CancellationToken)"/>
/// to the corresponding <see cref="JsonRpcMessage.ExecutionContext"/> emitted by the <see cref="MessageReader"/>.
/// </summary>
/// <remarks>
/// Defaults to <see langword="false"/>.
/// </remarks>
public bool FlowExecutionContextFromRequests { get; init; }
/// <summary>
/// Gets or sets a callback to be invoked before handling the initialize request.
/// </summary>
@ -55,9 +67,6 @@ public sealed class StreamableHttpServerTransport : ITransport
internal ChannelWriter<JsonRpcMessage> MessageWriter => _incomingChannel.Writer;
/// <inheritdoc/>
public string? SessionId { get; set; }
/// <summary>
/// Handles an optional SSE GET request a client using the Streamable HTTP transport might make by
/// writing any unsolicited JSON-RPC messages sent via <see cref="SendMessageAsync"/>