Fix request-scoped draft client capabilities (#1685)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Tarek Mahmoud Sayed <tarekms@ntdev.microsoft.com>
This commit is contained in:
parent
b2a40128fc
commit
a8d374b280
1 changed files with 306 additions and 40 deletions
|
|
@ -5,18 +5,66 @@ using System.Text.Json.Nodes;
|
|||
namespace ModelContextProtocol.Server;
|
||||
|
||||
#pragma warning disable MCPEXP002
|
||||
internal sealed class DestinationBoundMcpServer(McpServerImpl server, ITransport? transport) : McpServer
|
||||
internal sealed class DestinationBoundMcpServer(McpServerImpl server, ITransport? transport, JsonRpcMessageContext? requestContext = null) : McpServer
|
||||
#pragma warning restore MCPEXP002
|
||||
{
|
||||
private readonly bool _isJuly2026OrLaterRequest = server.IsJuly2026OrLaterProtocolRequest(requestContext);
|
||||
private readonly ClientCapabilities? _requestClientCapabilities = requestContext?.ClientCapabilities;
|
||||
private readonly Implementation? _requestClientInfo = requestContext?.ClientInfo;
|
||||
|
||||
public override string? SessionId => transport?.SessionId ?? server.SessionId;
|
||||
public override string? NegotiatedProtocolVersion => server.NegotiatedProtocolVersion;
|
||||
public override ClientCapabilities? ClientCapabilities => server.ClientCapabilities;
|
||||
public override Implementation? ClientInfo => server.ClientInfo;
|
||||
public override McpServerOptions ServerOptions => server.ServerOptions;
|
||||
public override IServiceProvider? Services => server.Services;
|
||||
[Obsolete(Obsoletions.DeprecatedLogging_Message, DiagnosticId = Obsoletions.Deprecated_DiagnosticId, UrlFormat = Obsoletions.Deprecated_Url)]
|
||||
public override LoggingLevel? LoggingLevel => server.LoggingLevel;
|
||||
|
||||
public override ClientCapabilities? ClientCapabilities
|
||||
{
|
||||
get
|
||||
{
|
||||
// In stateless transport mode, a single request does not have a persistent bidirectional channel.
|
||||
// Server-to-client requests (sampling, roots, elicitation) are unsupported in this mode and the
|
||||
// capability gates rely on a null ClientCapabilities value to report that unsupported-state path.
|
||||
if (!server.HasStatefulTransport())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// On protocol revision 2026-07-28+, client capabilities are request-scoped (_meta on each request)
|
||||
// and must not be inferred from prior requests. Missing per-request capabilities therefore means
|
||||
// "no declared capabilities for this request", represented by an empty object. A fresh instance is
|
||||
// returned deliberately: ClientCapabilities is a mutable DTO handed to user handlers, so a shared
|
||||
// static empty instance could be mutated and leak across requests.
|
||||
if (_isJuly2026OrLaterRequest)
|
||||
{
|
||||
return _requestClientCapabilities ?? new ClientCapabilities();
|
||||
}
|
||||
|
||||
// Legacy protocol behavior uses session-scoped capabilities established during initialize (or
|
||||
// pre-populated migration data), so ignore per-request values and return the server session state.
|
||||
return server.ClientCapabilities;
|
||||
}
|
||||
}
|
||||
|
||||
public override Implementation? ClientInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
// On protocol revision 2026-07-28+, client info is request-scoped (carried in each request's _meta),
|
||||
// mirroring how ClientCapabilities is resolved above. Return only this request's declared value and
|
||||
// do not fall back to shared session state, which under a stateful transport could belong to a
|
||||
// different concurrent request.
|
||||
if (_isJuly2026OrLaterRequest)
|
||||
{
|
||||
return _requestClientInfo;
|
||||
}
|
||||
|
||||
// Legacy protocol behavior uses session-scoped client info established during initialize.
|
||||
return server.ClientInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the MRTR context for the current request, if any.
|
||||
/// Set by <see cref="McpServerImpl.CreateDestinationBoundServer"/> when an MRTR-aware handler invocation is in progress.
|
||||
|
|
|
|||
Loading…
Reference in a new issue